ccxt 4.2.93 → 4.2.94

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.
@@ -7639,6 +7639,8 @@ class Exchange {
7639
7639
  'fetchClosedOrder': undefined,
7640
7640
  'fetchClosedOrders': undefined,
7641
7641
  'fetchClosedOrdersWs': undefined,
7642
+ 'fetchConvertCurrencies': undefined,
7643
+ 'fetchConvertQuote': undefined,
7642
7644
  'fetchCrossBorrowRate': undefined,
7643
7645
  'fetchCrossBorrowRates': undefined,
7644
7646
  'fetchCurrencies': 'emulated',
@@ -10398,6 +10400,16 @@ class Exchange {
10398
10400
  }
10399
10401
  return result;
10400
10402
  }
10403
+ marketsForSymbols(symbols = undefined) {
10404
+ if (symbols === undefined) {
10405
+ return symbols;
10406
+ }
10407
+ const result = [];
10408
+ for (let i = 0; i < symbols.length; i++) {
10409
+ result.push(this.market(symbols[i]));
10410
+ }
10411
+ return result;
10412
+ }
10401
10413
  marketSymbols(symbols = undefined, type = undefined, allowEmpty = true, sameTypeOnly = false, sameSubTypeOnly = false) {
10402
10414
  if (symbols === undefined) {
10403
10415
  if (!allowEmpty) {
@@ -11746,6 +11758,9 @@ class Exchange {
11746
11758
  async fetchOption(symbol, params = {}) {
11747
11759
  throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' fetchOption() is not supported yet');
11748
11760
  }
11761
+ async fetchConvertQuote(fromCode, toCode, amount = undefined, params = {}) {
11762
+ throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' fetchConvertQuote() is not supported yet');
11763
+ }
11749
11764
  async fetchDepositsWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
11750
11765
  /**
11751
11766
  * @method
@@ -12294,6 +12309,9 @@ class Exchange {
12294
12309
  const fees = await this.fetchTradingFees(params);
12295
12310
  return this.safeDict(fees, symbol);
12296
12311
  }
12312
+ async fetchConvertCurrencies(params = {}) {
12313
+ throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' fetchConvertCurrencies() is not supported yet');
12314
+ }
12297
12315
  parseOpenInterest(interest, market = undefined) {
12298
12316
  throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' parseOpenInterest () is not supported yet');
12299
12317
  }
@@ -12991,7 +13009,10 @@ class Exchange {
12991
13009
  return leverageStructures;
12992
13010
  }
12993
13011
  parseLeverage(leverage, market = undefined) {
12994
- throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' parseLeverage() is not supported yet');
13012
+ throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' parseLeverage () is not supported yet');
13013
+ }
13014
+ parseConversion(conversion, fromCurrency = undefined, toCurrency = undefined) {
13015
+ throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' parseConversion () is not supported yet');
12995
13016
  }
12996
13017
  convertExpireDate(date) {
12997
13018
  // parse YYMMDD to datetime string
@@ -18738,6 +18759,8 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
18738
18759
  'fetchCanceledOrders': 'emulated',
18739
18760
  'fetchClosedOrder': false,
18740
18761
  'fetchClosedOrders': 'emulated',
18762
+ 'fetchConvertCurrencies': true,
18763
+ 'fetchConvertQuote': false,
18741
18764
  'fetchCrossBorrowRate': true,
18742
18765
  'fetchCrossBorrowRates': false,
18743
18766
  'fetchCurrencies': true,
@@ -19637,6 +19660,7 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
19637
19660
  },
19638
19661
  'post': {
19639
19662
  'order/oco': 0.2,
19663
+ 'orderList/oco': 0.2,
19640
19664
  'sor/order': 0.2,
19641
19665
  'sor/order/test': 0.2,
19642
19666
  'order': 0.2,
@@ -22904,11 +22928,14 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
22904
22928
  'interval': this.safeString(this.timeframes, timeframe, timeframe),
22905
22929
  'limit': limit,
22906
22930
  };
22931
+ const marketId = market['id'];
22907
22932
  if (price === 'index') {
22908
- request['pair'] = market['id']; // Index price takes this argument instead of symbol
22933
+ const parts = marketId.split('_');
22934
+ const pair = this.safeString(parts, 0);
22935
+ request['pair'] = pair; // Index price takes this argument instead of symbol
22909
22936
  }
22910
22937
  else {
22911
- request['symbol'] = market['id'];
22938
+ request['symbol'] = marketId;
22912
22939
  }
22913
22940
  // const duration = this.parseTimeframe (timeframe);
22914
22941
  if (since !== undefined) {
@@ -31253,6 +31280,61 @@ class binance extends _abstract_binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
31253
31280
  const modifications = this.parseMarginModifications(response);
31254
31281
  return this.filterBySymbolSinceLimit(modifications, symbol, since, limit);
31255
31282
  }
31283
+ async fetchConvertCurrencies(params = {}) {
31284
+ /**
31285
+ * @method
31286
+ * @name binance#fetchConvertCurrencies
31287
+ * @description fetches all available currencies that can be converted
31288
+ * @see https://binance-docs.github.io/apidocs/spot/en/#query-order-quantity-precision-per-asset-user_data
31289
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
31290
+ * @returns {object} an associative dictionary of currencies
31291
+ */
31292
+ await this.loadMarkets();
31293
+ const response = await this.sapiGetConvertAssetInfo(params);
31294
+ //
31295
+ // [
31296
+ // {
31297
+ // "asset": "BTC",
31298
+ // "fraction": 8
31299
+ // },
31300
+ // ]
31301
+ //
31302
+ const result = {};
31303
+ for (let i = 0; i < response.length; i++) {
31304
+ const entry = response[i];
31305
+ const id = this.safeString(entry, 'asset');
31306
+ const code = this.safeCurrencyCode(id);
31307
+ result[code] = {
31308
+ 'info': entry,
31309
+ 'id': id,
31310
+ 'code': code,
31311
+ 'networks': undefined,
31312
+ 'type': undefined,
31313
+ 'name': undefined,
31314
+ 'active': undefined,
31315
+ 'deposit': undefined,
31316
+ 'withdraw': undefined,
31317
+ 'fee': undefined,
31318
+ 'precision': this.safeInteger(entry, 'fraction'),
31319
+ 'limits': {
31320
+ 'amount': {
31321
+ 'min': undefined,
31322
+ 'max': undefined,
31323
+ },
31324
+ 'withdraw': {
31325
+ 'min': undefined,
31326
+ 'max': undefined,
31327
+ },
31328
+ 'deposit': {
31329
+ 'min': undefined,
31330
+ 'max': undefined,
31331
+ },
31332
+ },
31333
+ 'created': undefined,
31334
+ };
31335
+ }
31336
+ return result;
31337
+ }
31256
31338
  }
31257
31339
 
31258
31340
 
@@ -45895,6 +45977,8 @@ class bitget extends _abstract_bitget_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
45895
45977
  'fetchCanceledAndClosedOrders': true,
45896
45978
  'fetchCanceledOrders': true,
45897
45979
  'fetchClosedOrders': true,
45980
+ 'fetchConvertCurrencies': true,
45981
+ 'fetchConvertQuote': true,
45898
45982
  'fetchCrossBorrowRate': true,
45899
45983
  'fetchCrossBorrowRates': false,
45900
45984
  'fetchCurrencies': true,
@@ -54274,6 +54358,143 @@ class bitget extends _abstract_bitget_js__WEBPACK_IMPORTED_MODULE_0__/* ["defaul
54274
54358
  'marginMode': marginType,
54275
54359
  };
54276
54360
  }
54361
+ async fetchConvertQuote(fromCode, toCode, amount = undefined, params = {}) {
54362
+ /**
54363
+ * @method
54364
+ * @name bitget#fetchConvertQuote
54365
+ * @description fetch a quote for converting from one currency to another
54366
+ * @see https://www.bitget.com/api-doc/common/convert/Get-Quoted-Price
54367
+ * @param {string} fromCode the currency that you want to sell and convert from
54368
+ * @param {string} toCode the currency that you want to buy and convert into
54369
+ * @param {float} [amount] how much you want to trade in units of the from currency
54370
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
54371
+ * @returns {object} a [conversion structure]{@link https://docs.ccxt.com/#/?id=conversion-structure}
54372
+ */
54373
+ await this.loadMarkets();
54374
+ const request = {
54375
+ 'fromCoin': fromCode.toUpperCase(),
54376
+ 'toCoin': toCode.toUpperCase(),
54377
+ 'fromCoinSize': this.numberToString(amount),
54378
+ };
54379
+ const response = await this.privateConvertGetV2ConvertQuotedPrice(this.extend(request, params));
54380
+ //
54381
+ // {
54382
+ // "code": "00000",
54383
+ // "msg": "success",
54384
+ // "requestTime": 1712121940158,
54385
+ // "data": {
54386
+ // "fromCoin": "USDT",
54387
+ // "fromCoinSize": "5",
54388
+ // "cnvtPrice": "0.9993007892377704",
54389
+ // "toCoin": "USDC",
54390
+ // "toCoinSize": "4.99650394",
54391
+ // "traceId": "1159288930228187140",
54392
+ // "fee": "0"
54393
+ // }
54394
+ // }
54395
+ //
54396
+ const data = this.safeDict(response, 'data', {});
54397
+ const fromCurrencyId = this.safeString(data, 'fromCoin', fromCode);
54398
+ const fromCurrency = this.currency(fromCurrencyId);
54399
+ const toCurrencyId = this.safeString(data, 'toCoin', toCode);
54400
+ const toCurrency = this.currency(toCurrencyId);
54401
+ return this.parseConversion(data, fromCurrency, toCurrency);
54402
+ }
54403
+ parseConversion(conversion, fromCurrency = undefined, toCurrency = undefined) {
54404
+ //
54405
+ // fetchConvertQuote
54406
+ //
54407
+ // {
54408
+ // "fromCoin": "USDT",
54409
+ // "fromCoinSize": "5",
54410
+ // "cnvtPrice": "0.9993007892377704",
54411
+ // "toCoin": "USDC",
54412
+ // "toCoinSize": "4.99650394",
54413
+ // "traceId": "1159288930228187140",
54414
+ // "fee": "0"
54415
+ // }
54416
+ //
54417
+ const timestamp = this.safeInteger(conversion, 'ts');
54418
+ const fromCoin = this.safeString(conversion, 'fromCoin');
54419
+ const fromCode = this.safeCurrencyCode(fromCoin, fromCurrency);
54420
+ const to = this.safeString(conversion, 'toCoin');
54421
+ const toCode = this.safeCurrencyCode(to, toCurrency);
54422
+ return {
54423
+ 'info': conversion,
54424
+ 'timestamp': timestamp,
54425
+ 'datetime': this.iso8601(timestamp),
54426
+ 'id': this.safeString(conversion, 'traceId'),
54427
+ 'fromCurrency': fromCode,
54428
+ 'fromAmount': this.safeNumber(conversion, 'fromCoinSize'),
54429
+ 'toCurrency': toCode,
54430
+ 'toAmount': this.safeNumber(conversion, 'toCoinSize'),
54431
+ 'price': this.safeNumber(conversion, 'cnvtPrice'),
54432
+ 'fee': this.safeNumber(conversion, 'fee'),
54433
+ };
54434
+ }
54435
+ async fetchConvertCurrencies(params = {}) {
54436
+ /**
54437
+ * @method
54438
+ * @name bitget#fetchConvertCurrencies
54439
+ * @description fetches all available currencies that can be converted
54440
+ * @see https://www.bitget.com/api-doc/common/convert/Get-Convert-Currencies
54441
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
54442
+ * @returns {object} an associative dictionary of currencies
54443
+ */
54444
+ await this.loadMarkets();
54445
+ const response = await this.privateConvertGetV2ConvertCurrencies(params);
54446
+ //
54447
+ // {
54448
+ // "code": "00000",
54449
+ // "msg": "success",
54450
+ // "requestTime": 1712121755897,
54451
+ // "data": [
54452
+ // {
54453
+ // "coin": "BTC",
54454
+ // "available": "0.00009850",
54455
+ // "maxAmount": "0.756266",
54456
+ // "minAmount": "0.00001"
54457
+ // },
54458
+ // ]
54459
+ // }
54460
+ //
54461
+ const result = {};
54462
+ const data = this.safeList(response, 'data', []);
54463
+ for (let i = 0; i < data.length; i++) {
54464
+ const entry = data[i];
54465
+ const id = this.safeString(entry, 'coin');
54466
+ const code = this.safeCurrencyCode(id);
54467
+ result[code] = {
54468
+ 'info': entry,
54469
+ 'id': id,
54470
+ 'code': code,
54471
+ 'networks': undefined,
54472
+ 'type': undefined,
54473
+ 'name': undefined,
54474
+ 'active': undefined,
54475
+ 'deposit': undefined,
54476
+ 'withdraw': this.safeNumber(entry, 'available'),
54477
+ 'fee': undefined,
54478
+ 'precision': undefined,
54479
+ 'limits': {
54480
+ 'amount': {
54481
+ 'min': this.safeNumber(entry, 'minAmount'),
54482
+ 'max': this.safeNumber(entry, 'maxAmount'),
54483
+ },
54484
+ 'withdraw': {
54485
+ 'min': undefined,
54486
+ 'max': undefined,
54487
+ },
54488
+ 'deposit': {
54489
+ 'min': undefined,
54490
+ 'max': undefined,
54491
+ },
54492
+ },
54493
+ 'created': undefined,
54494
+ };
54495
+ }
54496
+ return result;
54497
+ }
54277
54498
  handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
54278
54499
  if (!response) {
54279
54500
  return undefined; // fallback to default error handler
@@ -206973,6 +207194,8 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
206973
207194
  'fetchCanceledOrders': true,
206974
207195
  'fetchClosedOrder': undefined,
206975
207196
  'fetchClosedOrders': true,
207197
+ 'fetchConvertCurrencies': true,
207198
+ 'fetchConvertQuote': true,
206976
207199
  'fetchCrossBorrowRate': true,
206977
207200
  'fetchCrossBorrowRates': true,
206978
207201
  'fetchCurrencies': true,
@@ -214517,6 +214740,157 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
214517
214740
  'quoteVolume': undefined,
214518
214741
  };
214519
214742
  }
214743
+ async fetchConvertQuote(fromCode, toCode, amount = undefined, params = {}) {
214744
+ /**
214745
+ * @method
214746
+ * @name okx#fetchConvertQuote
214747
+ * @description fetch a quote for converting from one currency to another
214748
+ * @see https://www.okx.com/docs-v5/en/#funding-account-rest-api-estimate-quote
214749
+ * @param {string} fromCode the currency that you want to sell and convert from
214750
+ * @param {string} toCode the currency that you want to buy and convert into
214751
+ * @param {float} [amount] how much you want to trade in units of the from currency
214752
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
214753
+ * @returns {object} a [conversion structure]{@link https://docs.ccxt.com/#/?id=conversion-structure}
214754
+ */
214755
+ await this.loadMarkets();
214756
+ const request = {
214757
+ 'baseCcy': fromCode.toUpperCase(),
214758
+ 'quoteCcy': toCode.toUpperCase(),
214759
+ 'rfqSzCcy': fromCode.toUpperCase(),
214760
+ 'rfqSz': this.numberToString(amount),
214761
+ 'side': 'sell',
214762
+ };
214763
+ const response = await this.privatePostAssetConvertEstimateQuote(this.extend(request, params));
214764
+ //
214765
+ // {
214766
+ // "code": "0",
214767
+ // "data": [
214768
+ // {
214769
+ // "baseCcy": "ETH",
214770
+ // "baseSz": "0.01023052",
214771
+ // "clQReqId": "",
214772
+ // "cnvtPx": "2932.40104429",
214773
+ // "origRfqSz": "30",
214774
+ // "quoteCcy": "USDT",
214775
+ // "quoteId": "quoterETH-USDT16461885104612381",
214776
+ // "quoteSz": "30",
214777
+ // "quoteTime": "1646188510461",
214778
+ // "rfqSz": "30",
214779
+ // "rfqSzCcy": "USDT",
214780
+ // "side": "buy",
214781
+ // "ttlMs": "10000"
214782
+ // }
214783
+ // ],
214784
+ // "msg": ""
214785
+ // }
214786
+ //
214787
+ const data = this.safeList(response, 'data', []);
214788
+ const result = this.safeDict(data, 0, {});
214789
+ const fromCurrencyId = this.safeString(result, 'baseCcy', fromCode);
214790
+ const fromCurrency = this.currency(fromCurrencyId);
214791
+ const toCurrencyId = this.safeString(result, 'quoteCcy', toCode);
214792
+ const toCurrency = this.currency(toCurrencyId);
214793
+ return this.parseConversion(result, fromCurrency, toCurrency);
214794
+ }
214795
+ parseConversion(conversion, fromCurrency = undefined, toCurrency = undefined) {
214796
+ //
214797
+ // fetchConvertQuote
214798
+ //
214799
+ // {
214800
+ // "baseCcy": "ETH",
214801
+ // "baseSz": "0.01023052",
214802
+ // "clQReqId": "",
214803
+ // "cnvtPx": "2932.40104429",
214804
+ // "origRfqSz": "30",
214805
+ // "quoteCcy": "USDT",
214806
+ // "quoteId": "quoterETH-USDT16461885104612381",
214807
+ // "quoteSz": "30",
214808
+ // "quoteTime": "1646188510461",
214809
+ // "rfqSz": "30",
214810
+ // "rfqSzCcy": "USDT",
214811
+ // "side": "buy",
214812
+ // "ttlMs": "10000"
214813
+ // }
214814
+ //
214815
+ const timestamp = this.safeInteger(conversion, 'quoteTime');
214816
+ const fromCoin = this.safeString(conversion, 'baseCcy');
214817
+ const fromCode = this.safeCurrencyCode(fromCoin, fromCurrency);
214818
+ const to = this.safeString(conversion, 'quoteCcy');
214819
+ const toCode = this.safeCurrencyCode(to, toCurrency);
214820
+ return {
214821
+ 'info': conversion,
214822
+ 'timestamp': timestamp,
214823
+ 'datetime': this.iso8601(timestamp),
214824
+ 'id': this.safeString(conversion, 'clQReqId'),
214825
+ 'fromCurrency': fromCode,
214826
+ 'fromAmount': this.safeNumber(conversion, 'baseSz'),
214827
+ 'toCurrency': toCode,
214828
+ 'toAmount': this.safeNumber(conversion, 'quoteSz'),
214829
+ 'price': this.safeNumber(conversion, 'cnvtPx'),
214830
+ 'fee': undefined,
214831
+ };
214832
+ }
214833
+ async fetchConvertCurrencies(params = {}) {
214834
+ /**
214835
+ * @method
214836
+ * @name okx#fetchConvertCurrencies
214837
+ * @description fetches all available currencies that can be converted
214838
+ * @see https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-convert-currencies
214839
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
214840
+ * @returns {object} an associative dictionary of currencies
214841
+ */
214842
+ await this.loadMarkets();
214843
+ const response = await this.privateGetAssetConvertCurrencies(params);
214844
+ //
214845
+ // {
214846
+ // "code": "0",
214847
+ // "data": [
214848
+ // {
214849
+ // "ccy": "BTC",
214850
+ // "max": "",
214851
+ // "min": ""
214852
+ // },
214853
+ // ],
214854
+ // "msg": ""
214855
+ // }
214856
+ //
214857
+ const result = {};
214858
+ const data = this.safeList(response, 'data', []);
214859
+ for (let i = 0; i < data.length; i++) {
214860
+ const entry = data[i];
214861
+ const id = this.safeString(entry, 'ccy');
214862
+ const code = this.safeCurrencyCode(id);
214863
+ result[code] = {
214864
+ 'info': entry,
214865
+ 'id': id,
214866
+ 'code': code,
214867
+ 'networks': undefined,
214868
+ 'type': undefined,
214869
+ 'name': undefined,
214870
+ 'active': undefined,
214871
+ 'deposit': undefined,
214872
+ 'withdraw': undefined,
214873
+ 'fee': undefined,
214874
+ 'precision': undefined,
214875
+ 'limits': {
214876
+ 'amount': {
214877
+ 'min': this.safeNumber(entry, 'min'),
214878
+ 'max': this.safeNumber(entry, 'max'),
214879
+ },
214880
+ 'withdraw': {
214881
+ 'min': undefined,
214882
+ 'max': undefined,
214883
+ },
214884
+ 'deposit': {
214885
+ 'min': undefined,
214886
+ 'max': undefined,
214887
+ },
214888
+ },
214889
+ 'created': undefined,
214890
+ };
214891
+ }
214892
+ return result;
214893
+ }
214520
214894
  handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
214521
214895
  if (!response) {
214522
214896
  return undefined; // fallback to default error handler
@@ -264020,10 +264394,12 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
264020
264394
  'watchMyTrades': true,
264021
264395
  'watchOHLCV': true,
264022
264396
  'watchOrderBook': true,
264397
+ 'watchOrderBookForSymbols': true,
264023
264398
  'watchOrders': true,
264024
264399
  'watchTicker': true,
264025
- 'watchTickers': false,
264400
+ 'watchTickers': true,
264026
264401
  'watchTrades': true,
264402
+ 'watchTradesForSymbols': true,
264027
264403
  'createOrderWs': true,
264028
264404
  'editOrderWs': true,
264029
264405
  'cancelOrderWs': true,
@@ -264314,10 +264690,9 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
264314
264690
  // ]
264315
264691
  //
264316
264692
  const wsName = message[3];
264317
- const name = 'ticker';
264318
- const messageHash = name + ':' + wsName;
264319
264693
  const market = this.safeValue(this.options['marketsByWsName'], wsName);
264320
264694
  const symbol = market['symbol'];
264695
+ const messageHash = this.getMessageHash('ticker', undefined, symbol);
264321
264696
  const ticker = message[1];
264322
264697
  const vwap = this.safeString(ticker['p'], 0);
264323
264698
  let quoteVolume = undefined;
@@ -264348,9 +264723,6 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
264348
264723
  'quoteVolume': quoteVolume,
264349
264724
  'info': ticker,
264350
264725
  });
264351
- // todo add support for multiple tickers (may be tricky)
264352
- // kraken confirms multi-pair subscriptions separately one by one
264353
- // trigger correct watchTickers calls upon receiving any of symbols
264354
264726
  this.tickers[symbol] = result;
264355
264727
  client.resolve(result, messageHash);
264356
264728
  }
@@ -264368,9 +264740,9 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
264368
264740
  //
264369
264741
  const wsName = this.safeString(message, 3);
264370
264742
  const name = this.safeString(message, 2);
264371
- const messageHash = name + ':' + wsName;
264372
264743
  const market = this.safeValue(this.options['marketsByWsName'], wsName);
264373
264744
  const symbol = market['symbol'];
264745
+ const messageHash = this.getMessageHash(name, undefined, symbol);
264374
264746
  let stored = this.safeValue(this.trades, symbol);
264375
264747
  if (stored === undefined) {
264376
264748
  const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
@@ -264471,25 +264843,61 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
264471
264843
  * @param {object} [params] extra parameters specific to the exchange API endpoint
264472
264844
  * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
264473
264845
  */
264474
- return await this.watchPublic('ticker', symbol, params);
264846
+ await this.loadMarkets();
264847
+ symbol = this.symbol(symbol);
264848
+ const tickers = await this.watchTickers([symbol], params);
264849
+ return tickers[symbol];
264850
+ }
264851
+ async watchTickers(symbols = undefined, params = {}) {
264852
+ /**
264853
+ * @method
264854
+ * @name kraken#watchTickers
264855
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
264856
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
264857
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
264858
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
264859
+ */
264860
+ await this.loadMarkets();
264861
+ symbols = this.marketSymbols(symbols, undefined, false);
264862
+ const ticker = await this.watchMultiHelper('ticker', 'ticker', symbols, undefined, params);
264863
+ if (this.newUpdates) {
264864
+ const result = {};
264865
+ result[ticker['symbol']] = ticker;
264866
+ return result;
264867
+ }
264868
+ return this.filterByArray(this.tickers, 'symbol', symbols);
264475
264869
  }
264476
264870
  async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
264477
264871
  /**
264478
264872
  * @method
264479
264873
  * @name kraken#watchTrades
264480
264874
  * @description get the list of most recent trades for a particular symbol
264875
+ * @see https://docs.kraken.com/websockets/#message-trade
264481
264876
  * @param {string} symbol unified symbol of the market to fetch trades for
264482
264877
  * @param {int} [since] timestamp in ms of the earliest trade to fetch
264483
264878
  * @param {int} [limit] the maximum amount of trades to fetch
264484
264879
  * @param {object} [params] extra parameters specific to the exchange API endpoint
264485
264880
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
264486
264881
  */
264487
- await this.loadMarkets();
264488
- symbol = this.symbol(symbol);
264489
- const name = 'trade';
264490
- const trades = await this.watchPublic(name, symbol, params);
264882
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
264883
+ }
264884
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
264885
+ /**
264886
+ * @method
264887
+ * @name kraken#watchTradesForSymbols
264888
+ * @see https://docs.kraken.com/websockets/#message-trade
264889
+ * @description get the list of most recent trades for a list of symbols
264890
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
264891
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
264892
+ * @param {int} [limit] the maximum amount of trades to fetch
264893
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
264894
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
264895
+ */
264896
+ const trades = await this.watchMultiHelper('trade', 'trade', symbols, undefined, params);
264491
264897
  if (this.newUpdates) {
264492
- limit = trades.getLimit(symbol, limit);
264898
+ const first = this.safeList(trades, 0);
264899
+ const tradeSymbol = this.safeString(first, 'symbol');
264900
+ limit = trades.getLimit(tradeSymbol, limit);
264493
264901
  }
264494
264902
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
264495
264903
  }
@@ -264498,15 +264906,28 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
264498
264906
  * @method
264499
264907
  * @name kraken#watchOrderBook
264500
264908
  * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
264909
+ * @see https://docs.kraken.com/websockets/#message-book
264501
264910
  * @param {string} symbol unified symbol of the market to fetch the order book for
264502
264911
  * @param {int} [limit] the maximum amount of order book entries to return
264503
264912
  * @param {object} [params] extra parameters specific to the exchange API endpoint
264504
264913
  * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
264505
264914
  */
264506
- const name = 'book';
264915
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
264916
+ }
264917
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
264918
+ /**
264919
+ * @method
264920
+ * @name kraken#watchOrderBookForSymbols
264921
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
264922
+ * @see https://docs.kraken.com/websockets/#message-book
264923
+ * @param {string[]} symbols unified array of symbols
264924
+ * @param {int} [limit] the maximum amount of order book entries to return
264925
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
264926
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
264927
+ */
264507
264928
  const request = {};
264508
264929
  if (limit !== undefined) {
264509
- if ((limit === 10) || (limit === 25) || (limit === 100) || (limit === 500) || (limit === 1000)) {
264930
+ if (this.inArray(limit, [10, 25, 100, 500, 1000])) {
264510
264931
  request['subscription'] = {
264511
264932
  'depth': limit, // default 10, valid options 10, 25, 100, 500, 1000
264512
264933
  };
@@ -264515,7 +264936,7 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
264515
264936
  throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.NotSupported(this.id + ' watchOrderBook accepts limit values of 10, 25, 100, 500 and 1000 only');
264516
264937
  }
264517
264938
  }
264518
- const orderbook = await this.watchPublic(name, symbol, this.extend(request, params));
264939
+ const orderbook = await this.watchMultiHelper('orderbook', 'book', symbols, { 'limit': limit }, this.extend(request, params));
264519
264940
  return orderbook.limit();
264520
264941
  }
264521
264942
  async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
@@ -264644,7 +265065,7 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
264644
265065
  const market = this.safeValue(this.options['marketsByWsName'], wsName);
264645
265066
  const symbol = market['symbol'];
264646
265067
  let timestamp = undefined;
264647
- const messageHash = 'book:' + wsName;
265068
+ const messageHash = this.getMessageHash('orderbook', undefined, symbol);
264648
265069
  // if this is a snapshot
264649
265070
  if ('as' in message[1]) {
264650
265071
  // todo get depth from marketsByWsName
@@ -264725,6 +265146,7 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
264725
265146
  if (localChecksum !== c) {
264726
265147
  const error = new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.InvalidNonce(this.id + ' invalid checksum');
264727
265148
  client.reject(error, messageHash);
265149
+ return;
264728
265150
  }
264729
265151
  }
264730
265152
  orderbook['symbol'] = symbol;
@@ -265252,6 +265674,48 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
265252
265674
  'trades': trades,
265253
265675
  });
265254
265676
  }
265677
+ async watchMultiHelper(unifiedName, channelName, symbols = undefined, subscriptionArgs = undefined, params = {}) {
265678
+ await this.loadMarkets();
265679
+ // symbols are required
265680
+ symbols = this.marketSymbols(symbols, undefined, false, true, false);
265681
+ const messageHashes = [];
265682
+ for (let i = 0; i < symbols.length; i++) {
265683
+ messageHashes.push(this.getMessageHash(unifiedName, undefined, this.symbol(symbols[i])));
265684
+ }
265685
+ // for WS subscriptions, we can't use .marketIds (symbols), instead a custom is field needed
265686
+ const markets = this.marketsForSymbols(symbols);
265687
+ const wsMarketIds = [];
265688
+ for (let i = 0; i < markets.length; i++) {
265689
+ const wsMarketId = this.safeString(markets[i]['info'], 'wsname');
265690
+ wsMarketIds.push(wsMarketId);
265691
+ }
265692
+ const request = {
265693
+ 'event': 'subscribe',
265694
+ 'reqid': this.requestId(),
265695
+ 'pair': wsMarketIds,
265696
+ 'subscription': {
265697
+ 'name': channelName,
265698
+ },
265699
+ };
265700
+ const url = this.urls['api']['ws']['public'];
265701
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), messageHashes, subscriptionArgs);
265702
+ }
265703
+ getMessageHash(unifiedElementName, subChannelName = undefined, symbol = undefined) {
265704
+ // unifiedElementName can be : orderbook, trade, ticker, bidask ...
265705
+ // subChannelName only applies to channel that needs specific variation (i.e. depth_50, depth_100..) to be selected
265706
+ const withSymbol = symbol !== undefined;
265707
+ let messageHash = unifiedElementName;
265708
+ if (!withSymbol) {
265709
+ messageHash += 's';
265710
+ }
265711
+ else {
265712
+ messageHash += '@' + symbol;
265713
+ }
265714
+ if (subChannelName !== undefined) {
265715
+ messageHash += '#' + subChannelName;
265716
+ }
265717
+ return messageHash;
265718
+ }
265255
265719
  handleSubscriptionStatus(client, message) {
265256
265720
  //
265257
265721
  // public
@@ -265398,9 +265862,12 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
265398
265862
  'fetchTradesWs': false,
265399
265863
  'watchOHLCV': false,
265400
265864
  'watchOrderBook': true,
265865
+ 'watchOrderBookForSymbols': true,
265401
265866
  'watchTicker': true,
265402
265867
  'watchTickers': true,
265868
+ 'watchBidsAsks': true,
265403
265869
  'watchTrades': true,
265870
+ 'watchTradesForSymbols': true,
265404
265871
  'watchBalance': true,
265405
265872
  // 'watchStatus': true, // https://docs.futures.kraken.com/#websocket-api-public-feeds-heartbeat
265406
265873
  'watchOrders': true,
@@ -265421,12 +265888,6 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
265421
265888
  'OHLCVLimit': 1000,
265422
265889
  'connectionLimit': 100,
265423
265890
  'requestLimit': 100,
265424
- 'watchTicker': {
265425
- 'method': 'ticker', // or ticker_lite
265426
- },
265427
- 'watchTickers': {
265428
- 'method': 'ticker', // or ticker_lite
265429
- },
265430
265891
  'fetchBalance': {
265431
265892
  'type': undefined,
265432
265893
  },
@@ -265464,6 +265925,20 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
265464
265925
  }
265465
265926
  return future;
265466
265927
  }
265928
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
265929
+ /**
265930
+ * @method
265931
+ * @name krakenfutures#watchOrderBookForSymbols
265932
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
265933
+ * @see https://docs.futures.kraken.com/#websocket-api-public-feeds-challenge
265934
+ * @param {string[]} symbols unified array of symbols
265935
+ * @param {int} [limit] the maximum amount of order book entries to return
265936
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
265937
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
265938
+ */
265939
+ const orderbook = await this.watchMultiHelper('orderbook', 'book', symbols, { 'limit': limit }, params);
265940
+ return orderbook.limit();
265941
+ }
265467
265942
  async subscribePublic(name, symbols, params = {}) {
265468
265943
  /**
265469
265944
  * @ignore
@@ -265531,34 +266006,49 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
265531
266006
  * @param {object} [params] extra parameters specific to the exchange API endpoint
265532
266007
  * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
265533
266008
  */
265534
- const options = this.safeValue(this.options, 'watchTicker');
265535
- const method = this.safeString(options, 'method', 'ticker'); // or ticker_lite
265536
- const name = this.safeString(params, 'method', method);
265537
- params = this.omit(params, ['method']);
265538
- return await this.subscribePublic(name, [symbol], params);
266009
+ await this.loadMarkets();
266010
+ symbol = this.symbol(symbol);
266011
+ const tickers = await this.watchTickers([symbol], params);
266012
+ return tickers[symbol];
265539
266013
  }
265540
266014
  async watchTickers(symbols = undefined, params = {}) {
265541
266015
  /**
265542
266016
  * @method
265543
- * @name krakenfutures#watchTicker
266017
+ * @name krakenfutures#watchTickers
265544
266018
  * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
265545
- * @see https://docs.futures.kraken.com/#websocket-api-public-feeds-ticker-lite
266019
+ * @see https://docs.futures.kraken.com/#websocket-api-public-feeds-ticker
265546
266020
  * @param {string} symbol unified symbol of the market to fetch the ticker for
265547
266021
  * @param {object} [params] extra parameters specific to the exchange API endpoint
265548
266022
  * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
265549
266023
  */
265550
- const method = this.safeString(this.options, 'watchTickerMethod', 'ticker'); // or ticker_lite
265551
- const name = this.safeString2(params, 'method', 'watchTickerMethod', method);
265552
- params = this.omit(params, ['watchTickerMethod', 'method']);
266024
+ await this.loadMarkets();
265553
266025
  symbols = this.marketSymbols(symbols, undefined, false);
265554
- const ticker = await this.subscribePublic(name, symbols, params);
266026
+ const ticker = await this.watchMultiHelper('ticker', 'ticker', symbols, undefined, params);
265555
266027
  if (this.newUpdates) {
265556
- const tickers = {};
265557
- tickers[ticker['symbol']] = ticker;
265558
- return tickers;
266028
+ const result = {};
266029
+ result[ticker['symbol']] = ticker;
266030
+ return result;
265559
266031
  }
265560
266032
  return this.filterByArray(this.tickers, 'symbol', symbols);
265561
266033
  }
266034
+ async watchBidsAsks(symbols = undefined, params = {}) {
266035
+ /**
266036
+ * @method
266037
+ * @name krakenfutures#watchBidsAsks
266038
+ * @see https://docs.futures.kraken.com/#websocket-api-public-feeds-ticker-lite
266039
+ * @description watches best bid & ask for symbols
266040
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
266041
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
266042
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
266043
+ */
266044
+ const ticker = await this.watchMultiHelper('bidask', 'ticker_lite', symbols, undefined, params);
266045
+ if (this.newUpdates) {
266046
+ const result = {};
266047
+ result[ticker['symbol']] = ticker;
266048
+ return result;
266049
+ }
266050
+ return this.filterByArray(this.bidsasks, 'symbol', symbols);
266051
+ }
265562
266052
  async watchTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
265563
266053
  /**
265564
266054
  * @method
@@ -265571,11 +266061,25 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
265571
266061
  * @param {object} [params] extra parameters specific to the exchange API endpoint
265572
266062
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
265573
266063
  */
265574
- await this.loadMarkets();
265575
- const name = 'trade';
265576
- const trades = await this.subscribePublic(name, [symbol], params);
266064
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
266065
+ }
266066
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
266067
+ /**
266068
+ * @method
266069
+ * @name krakenfutures#watchTradesForSymbols
266070
+ * @see https://docs.futures.kraken.com/#websocket-api-public-feeds-trade
266071
+ * @description get the list of most recent trades for a list of symbols
266072
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
266073
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
266074
+ * @param {int} [limit] the maximum amount of trades to fetch
266075
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
266076
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
266077
+ */
266078
+ const trades = await this.watchMultiHelper('trade', 'trade', symbols, undefined, params);
265577
266079
  if (this.newUpdates) {
265578
- limit = trades.getLimit(symbol, limit);
266080
+ const first = this.safeList(trades, 0);
266081
+ const tradeSymbol = this.safeString(first, 'symbol');
266082
+ limit = trades.getLimit(tradeSymbol, limit);
265579
266083
  }
265580
266084
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
265581
266085
  }
@@ -265590,8 +266094,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
265590
266094
  * @param {object} [params] extra parameters specific to the exchange API endpoint
265591
266095
  * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
265592
266096
  */
265593
- const orderbook = await this.subscribePublic('book', [symbol], params);
265594
- return orderbook.limit();
266097
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
265595
266098
  }
265596
266099
  async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
265597
266100
  /**
@@ -265839,7 +266342,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
265839
266342
  if (marketId !== undefined) {
265840
266343
  const market = this.market(marketId);
265841
266344
  const symbol = market['symbol'];
265842
- const messageHash = 'trade:' + symbol;
266345
+ const messageHash = this.getMessageHash('trade', undefined, symbol);
265843
266346
  if (this.safeList(this.trades, symbol) === undefined) {
265844
266347
  const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
265845
266348
  this.trades[symbol] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCache */ .ZL(tradesLimit);
@@ -265861,7 +266364,6 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
265861
266364
  }
265862
266365
  client.resolve(tradesArray, messageHash);
265863
266366
  }
265864
- return message;
265865
266367
  }
265866
266368
  parseWsTrade(trade, market = undefined) {
265867
266369
  //
@@ -266287,7 +266789,16 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
266287
266789
  // "volumeQuote": 19628180
266288
266790
  // }
266289
266791
  //
266290
- // ticker_lite
266792
+ const marketId = this.safeString(message, 'product_id');
266793
+ if (marketId !== undefined) {
266794
+ const ticker = this.parseWsTicker(message);
266795
+ const symbol = ticker['symbol'];
266796
+ this.tickers[symbol] = ticker;
266797
+ const messageHash = this.getMessageHash('ticker', undefined, symbol);
266798
+ client.resolve(ticker, messageHash);
266799
+ }
266800
+ }
266801
+ handleBidAsk(client, message) {
266291
266802
  //
266292
266803
  // {
266293
266804
  // "feed": "ticker_lite",
@@ -266305,16 +266816,13 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
266305
266816
  // }
266306
266817
  //
266307
266818
  const marketId = this.safeString(message, 'product_id');
266308
- const feed = this.safeString(message, 'feed');
266309
266819
  if (marketId !== undefined) {
266310
266820
  const ticker = this.parseWsTicker(message);
266311
266821
  const symbol = ticker['symbol'];
266312
- this.tickers[symbol] = ticker;
266313
- const messageHash = feed + ':' + symbol;
266822
+ this.bidsasks[symbol] = ticker;
266823
+ const messageHash = this.getMessageHash('bidask', undefined, symbol);
266314
266824
  client.resolve(ticker, messageHash);
266315
266825
  }
266316
- client.resolve(this.tickers, feed);
266317
- return message;
266318
266826
  }
266319
266827
  parseWsTicker(ticker, market = undefined) {
266320
266828
  //
@@ -266426,14 +266934,14 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
266426
266934
  const marketId = this.safeString(message, 'product_id');
266427
266935
  const market = this.safeMarket(marketId);
266428
266936
  const symbol = market['symbol'];
266429
- const messageHash = 'book:' + symbol;
266430
- const subscription = this.safeValue(client.subscriptions, messageHash, {});
266937
+ const messageHash = this.getMessageHash('orderbook', undefined, symbol);
266938
+ const subscription = this.safeDict(client.subscriptions, messageHash, {});
266431
266939
  const limit = this.safeInteger(subscription, 'limit');
266432
266940
  const timestamp = this.safeInteger(message, 'timestamp');
266433
266941
  this.orderbooks[symbol] = this.orderBook({}, limit);
266434
266942
  const orderbook = this.orderbooks[symbol];
266435
- const bids = this.safeValue(message, 'bids');
266436
- const asks = this.safeValue(message, 'asks');
266943
+ const bids = this.safeList(message, 'bids');
266944
+ const asks = this.safeList(message, 'asks');
266437
266945
  for (let i = 0; i < bids.length; i++) {
266438
266946
  const bid = bids[i];
266439
266947
  const price = this.safeNumber(bid, 'price');
@@ -266468,7 +266976,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
266468
266976
  const marketId = this.safeString(message, 'product_id');
266469
266977
  const market = this.safeMarket(marketId);
266470
266978
  const symbol = market['symbol'];
266471
- const messageHash = 'book:' + symbol;
266979
+ const messageHash = this.getMessageHash('orderbook', undefined, symbol);
266472
266980
  const orderbook = this.orderbooks[symbol];
266473
266981
  const side = this.safeString(message, 'side');
266474
266982
  const price = this.safeNumber(message, 'price');
@@ -266795,6 +267303,39 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
266795
267303
  },
266796
267304
  });
266797
267305
  }
267306
+ async watchMultiHelper(unifiedName, channelName, symbols = undefined, subscriptionArgs = undefined, params = {}) {
267307
+ await this.loadMarkets();
267308
+ // symbols are required
267309
+ symbols = this.marketSymbols(symbols, undefined, false, true, false);
267310
+ const messageHashes = [];
267311
+ for (let i = 0; i < symbols.length; i++) {
267312
+ messageHashes.push(this.getMessageHash(unifiedName, undefined, this.symbol(symbols[i])));
267313
+ }
267314
+ const marketIds = this.marketIds(symbols);
267315
+ const request = {
267316
+ 'event': 'subscribe',
267317
+ 'feed': channelName,
267318
+ 'product_ids': marketIds,
267319
+ };
267320
+ const url = this.urls['api']['ws'];
267321
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), messageHashes, subscriptionArgs);
267322
+ }
267323
+ getMessageHash(unifiedElementName, subChannelName = undefined, symbol = undefined) {
267324
+ // unifiedElementName can be : orderbook, trade, ticker, bidask ...
267325
+ // subChannelName only applies to channel that needs specific variation (i.e. depth_50, depth_100..) to be selected
267326
+ const withSymbol = symbol !== undefined;
267327
+ let messageHash = unifiedElementName;
267328
+ if (!withSymbol) {
267329
+ messageHash += 's';
267330
+ }
267331
+ else {
267332
+ messageHash += ':' + symbol;
267333
+ }
267334
+ if (subChannelName !== undefined) {
267335
+ messageHash += '#' + subChannelName;
267336
+ }
267337
+ return messageHash;
267338
+ }
266798
267339
  handleErrorMessage(client, message) {
266799
267340
  //
266800
267341
  // {
@@ -266825,10 +267366,10 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
266825
267366
  const feed = this.safeString(message, 'feed');
266826
267367
  const methods = {
266827
267368
  'ticker': this.handleTicker,
267369
+ 'ticker_lite': this.handleBidAsk,
266828
267370
  'trade': this.handleTrade,
266829
267371
  'trade_snapshot': this.handleTrade,
266830
267372
  // 'heartbeat': this.handleStatus,
266831
- 'ticker_lite': this.handleTicker,
266832
267373
  'book': this.handleOrderBook,
266833
267374
  'book_snapshot': this.handleOrderBookSnapshot,
266834
267375
  'open_orders_verbose': this.handleOrder,
@@ -267065,22 +267606,46 @@ class kucoin extends _kucoin_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
267065
267606
  /**
267066
267607
  * @method
267067
267608
  * @name kucoin#watchTickers
267609
+ * @see https://www.kucoin.com/docs/websocket/spot-trading/public-channels/ticker
267068
267610
  * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
267069
267611
  * @param {string[]} symbols unified symbol of the market to fetch the ticker for
267070
267612
  * @param {object} [params] extra parameters specific to the exchange API endpoint
267613
+ * @param {string} [params.method] either '/market/snapshot' or '/market/ticker' default is '/market/ticker'
267071
267614
  * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
267072
267615
  */
267073
267616
  await this.loadMarkets();
267074
267617
  symbols = this.marketSymbols(symbols);
267075
- let messageHash = 'tickers';
267618
+ const messageHash = 'tickers';
267619
+ let method = undefined;
267620
+ [method, params] = this.handleOptionAndParams(params, 'watchTickers', 'method', '/market/ticker');
267621
+ const messageHashes = [];
267622
+ const topics = [];
267076
267623
  if (symbols !== undefined) {
267077
- messageHash = 'tickers::' + symbols.join(',');
267624
+ for (let i = 0; i < symbols.length; i++) {
267625
+ const symbol = symbols[i];
267626
+ messageHashes.push('ticker:' + symbol);
267627
+ const market = this.market(symbol);
267628
+ topics.push(method + ':' + market['id']);
267629
+ }
267078
267630
  }
267079
267631
  const url = await this.negotiate(false);
267080
- const topic = '/market/ticker:all';
267081
- const tickers = await this.subscribe(url, messageHash, topic, params);
267082
- if (this.newUpdates) {
267083
- return tickers;
267632
+ let tickers = undefined;
267633
+ if (symbols === undefined) {
267634
+ const allTopic = method + ':all';
267635
+ tickers = await this.subscribe(url, messageHash, allTopic, params);
267636
+ if (this.newUpdates) {
267637
+ return tickers;
267638
+ }
267639
+ }
267640
+ else {
267641
+ const marketIds = this.marketIds(symbols);
267642
+ const symbolsTopic = method + ':' + marketIds.join(',');
267643
+ tickers = await this.subscribeMultiple(url, messageHashes, symbolsTopic, topics, params);
267644
+ if (this.newUpdates) {
267645
+ const newDict = {};
267646
+ newDict[tickers['symbol']] = tickers;
267647
+ return newDict;
267648
+ }
267084
267649
  }
267085
267650
  return this.filterByArray(this.tickers, 'symbol', symbols);
267086
267651
  }
@@ -267164,19 +267729,6 @@ class kucoin extends _kucoin_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
267164
267729
  const allTickers = {};
267165
267730
  allTickers[symbol] = ticker;
267166
267731
  client.resolve(allTickers, 'tickers');
267167
- const messageHashes = this.findMessageHashes(client, 'tickers::');
267168
- for (let i = 0; i < messageHashes.length; i++) {
267169
- const currentMessageHash = messageHashes[i];
267170
- const parts = currentMessageHash.split('::');
267171
- const symbolsString = parts[1];
267172
- const symbols = symbolsString.split(',');
267173
- const tickers = this.filterByArray(this.tickers, 'symbol', symbols);
267174
- const tickersSymbols = Object.keys(tickers);
267175
- const numTickers = tickersSymbols.length;
267176
- if (numTickers > 0) {
267177
- client.resolve(tickers, currentMessageHash);
267178
- }
267179
- }
267180
267732
  }
267181
267733
  async watchBidsAsks(symbols = undefined, params = {}) {
267182
267734
  /**
@@ -312452,6 +313004,8 @@ class woo extends _abstract_woo_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
312452
313004
  'fetchCanceledOrders': false,
312453
313005
  'fetchClosedOrder': false,
312454
313006
  'fetchClosedOrders': true,
313007
+ 'fetchConvertCurrencies': true,
313008
+ 'fetchConvertQuote': true,
312455
313009
  'fetchCurrencies': true,
312456
313010
  'fetchDepositAddress': true,
312457
313011
  'fetchDeposits': true,
@@ -315380,6 +315934,143 @@ class woo extends _abstract_woo_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
315380
315934
  'takeProfitPrice': undefined,
315381
315935
  });
315382
315936
  }
315937
+ async fetchConvertQuote(fromCode, toCode, amount = undefined, params = {}) {
315938
+ /**
315939
+ * @method
315940
+ * @name woo#fetchConvertQuote
315941
+ * @description fetch a quote for converting from one currency to another
315942
+ * @see https://docs.woo.org/#get-quote-rfq
315943
+ * @param {string} fromCode the currency that you want to sell and convert from
315944
+ * @param {string} toCode the currency that you want to buy and convert into
315945
+ * @param {float} [amount] how much you want to trade in units of the from currency
315946
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
315947
+ * @returns {object} a [conversion structure]{@link https://docs.ccxt.com/#/?id=conversion-structure}
315948
+ */
315949
+ await this.loadMarkets();
315950
+ const request = {
315951
+ 'sellToken': fromCode.toUpperCase(),
315952
+ 'buyToken': toCode.toUpperCase(),
315953
+ 'sellQuantity': this.numberToString(amount),
315954
+ };
315955
+ const response = await this.v3PrivateGetConvertRfq(this.extend(request, params));
315956
+ //
315957
+ // {
315958
+ // "success": true,
315959
+ // "data": {
315960
+ // "quoteId": 123123123,
315961
+ // "counterPartyId": "",
315962
+ // "sellToken": "ETH",
315963
+ // "sellQuantity": "0.0445",
315964
+ // "buyToken": "USDT",
315965
+ // "buyQuantity": "33.45",
315966
+ // "buyPrice": "6.77",
315967
+ // "expireTimestamp": 1659084466000,
315968
+ // "message": 1659084466000
315969
+ // }
315970
+ // }
315971
+ //
315972
+ const data = this.safeDict(response, 'data', {});
315973
+ const fromCurrencyId = this.safeString(data, 'sellToken', fromCode);
315974
+ const fromCurrency = this.currency(fromCurrencyId);
315975
+ const toCurrencyId = this.safeString(data, 'buyToken', toCode);
315976
+ const toCurrency = this.currency(toCurrencyId);
315977
+ return this.parseConversion(data, fromCurrency, toCurrency);
315978
+ }
315979
+ parseConversion(conversion, fromCurrency = undefined, toCurrency = undefined) {
315980
+ //
315981
+ // fetchConvertQuote
315982
+ //
315983
+ // {
315984
+ // "quoteId": 123123123,
315985
+ // "counterPartyId": "",
315986
+ // "sellToken": "ETH",
315987
+ // "sellQuantity": "0.0445",
315988
+ // "buyToken": "USDT",
315989
+ // "buyQuantity": "33.45",
315990
+ // "buyPrice": "6.77",
315991
+ // "expireTimestamp": 1659084466000,
315992
+ // "message": 1659084466000
315993
+ // }
315994
+ //
315995
+ const timestamp = this.safeInteger(conversion, 'expireTimestamp');
315996
+ const fromCoin = this.safeString(conversion, 'sellToken');
315997
+ const fromCode = this.safeCurrencyCode(fromCoin, fromCurrency);
315998
+ const to = this.safeString(conversion, 'buyToken');
315999
+ const toCode = this.safeCurrencyCode(to, toCurrency);
316000
+ return {
316001
+ 'info': conversion,
316002
+ 'timestamp': timestamp,
316003
+ 'datetime': this.iso8601(timestamp),
316004
+ 'id': this.safeString(conversion, 'quoteId'),
316005
+ 'fromCurrency': fromCode,
316006
+ 'fromAmount': this.safeNumber(conversion, 'sellQuantity'),
316007
+ 'toCurrency': toCode,
316008
+ 'toAmount': this.safeNumber(conversion, 'buyQuantity'),
316009
+ 'price': this.safeNumber(conversion, 'buyPrice'),
316010
+ 'fee': undefined,
316011
+ };
316012
+ }
316013
+ async fetchConvertCurrencies(params = {}) {
316014
+ /**
316015
+ * @method
316016
+ * @name woo#fetchConvertCurrencies
316017
+ * @description fetches all available currencies that can be converted
316018
+ * @see https://docs.woo.org/#get-quote-asset-info
316019
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
316020
+ * @returns {object} an associative dictionary of currencies
316021
+ */
316022
+ await this.loadMarkets();
316023
+ const response = await this.v3PrivateGetConvertAssetInfo(params);
316024
+ //
316025
+ // {
316026
+ // "success": true,
316027
+ // "rows": [
316028
+ // {
316029
+ // "token": "BTC",
316030
+ // "tick": 0.0001,
316031
+ // "createdTime": "1575014248.99", // Unix epoch time in seconds
316032
+ // "updatedTime": "1575014248.99" // Unix epoch time in seconds
316033
+ // },
316034
+ // ]
316035
+ // }
316036
+ //
316037
+ const result = {};
316038
+ const data = this.safeList(response, 'rows', []);
316039
+ for (let i = 0; i < data.length; i++) {
316040
+ const entry = data[i];
316041
+ const id = this.safeString(entry, 'token');
316042
+ const code = this.safeCurrencyCode(id);
316043
+ result[code] = {
316044
+ 'info': entry,
316045
+ 'id': id,
316046
+ 'code': code,
316047
+ 'networks': undefined,
316048
+ 'type': undefined,
316049
+ 'name': undefined,
316050
+ 'active': undefined,
316051
+ 'deposit': undefined,
316052
+ 'withdraw': undefined,
316053
+ 'fee': undefined,
316054
+ 'precision': this.safeNumber(entry, 'tick'),
316055
+ 'limits': {
316056
+ 'amount': {
316057
+ 'min': undefined,
316058
+ 'max': undefined,
316059
+ },
316060
+ 'withdraw': {
316061
+ 'min': undefined,
316062
+ 'max': undefined,
316063
+ },
316064
+ 'deposit': {
316065
+ 'min': undefined,
316066
+ 'max': undefined,
316067
+ },
316068
+ },
316069
+ 'created': this.safeTimestamp(entry, 'createdTime'),
316070
+ };
316071
+ }
316072
+ return result;
316073
+ }
315383
316074
  defaultNetworkCodeForCurrency(code) {
315384
316075
  const currencyItem = this.currency(code);
315385
316076
  const networks = currencyItem['networks'];
@@ -325553,7 +326244,7 @@ SOFTWARE.
325553
326244
 
325554
326245
  //-----------------------------------------------------------------------------
325555
326246
  // this is updated by vss.js when building
325556
- const version = '4.2.93';
326247
+ const version = '4.2.94';
325557
326248
  _src_base_Exchange_js__WEBPACK_IMPORTED_MODULE_0__/* .Exchange */ .e.ccxtVersion = version;
325558
326249
  //-----------------------------------------------------------------------------
325559
326250