ccxt 4.3.62 → 4.3.63

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 (61) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +2 -1
  4. package/dist/cjs/src/ace.js +34 -15
  5. package/dist/cjs/src/base/Exchange.js +8 -1
  6. package/dist/cjs/src/base/errors.js +8 -1
  7. package/dist/cjs/src/binance.js +6 -9
  8. package/dist/cjs/src/bingx.js +466 -151
  9. package/dist/cjs/src/cryptocom.js +18 -2
  10. package/dist/cjs/src/mercado.js +5 -1
  11. package/dist/cjs/src/pro/binance.js +58 -34
  12. package/dist/cjs/src/pro/bitfinex2.js +6 -3
  13. package/dist/cjs/src/pro/bitget.js +4 -1
  14. package/dist/cjs/src/pro/bitvavo.js +1 -1
  15. package/dist/cjs/src/pro/bybit.js +44 -18
  16. package/dist/cjs/src/pro/cryptocom.js +7 -1
  17. package/dist/cjs/src/pro/gate.js +6 -2
  18. package/dist/cjs/src/pro/htx.js +5 -1
  19. package/dist/cjs/src/pro/independentreserve.js +5 -3
  20. package/dist/cjs/src/pro/kraken.js +82 -4
  21. package/dist/cjs/src/pro/okx.js +3 -3
  22. package/dist/cjs/src/pro/poloniexfutures.js +5 -1
  23. package/dist/cjs/src/pro/woofipro.js +1 -1
  24. package/dist/cjs/src/woo.js +313 -81
  25. package/js/ccxt.d.ts +3 -3
  26. package/js/ccxt.js +3 -3
  27. package/js/src/abstract/cryptocom.d.ts +11 -0
  28. package/js/src/abstract/woo.d.ts +3 -0
  29. package/js/src/ace.js +34 -15
  30. package/js/src/base/Exchange.d.ts +1 -0
  31. package/js/src/base/Exchange.js +8 -1
  32. package/js/src/base/errorHierarchy.d.ts +3 -1
  33. package/js/src/base/errorHierarchy.js +3 -1
  34. package/js/src/base/errors.d.ts +5 -1
  35. package/js/src/base/errors.js +8 -2
  36. package/js/src/binance.js +6 -9
  37. package/js/src/bingx.d.ts +1 -0
  38. package/js/src/bingx.js +466 -151
  39. package/js/src/coinbaseinternational.d.ts +1 -1
  40. package/js/src/cryptocom.js +18 -2
  41. package/js/src/mercado.js +5 -1
  42. package/js/src/pro/binance.d.ts +1 -0
  43. package/js/src/pro/binance.js +59 -35
  44. package/js/src/pro/bitfinex2.js +7 -4
  45. package/js/src/pro/bitget.js +5 -2
  46. package/js/src/pro/bitvavo.js +1 -1
  47. package/js/src/pro/bybit.d.ts +1 -0
  48. package/js/src/pro/bybit.js +44 -18
  49. package/js/src/pro/cryptocom.js +8 -2
  50. package/js/src/pro/gate.js +7 -3
  51. package/js/src/pro/htx.js +6 -2
  52. package/js/src/pro/independentreserve.js +6 -4
  53. package/js/src/pro/kraken.d.ts +3 -1
  54. package/js/src/pro/kraken.js +83 -5
  55. package/js/src/pro/okx.js +4 -4
  56. package/js/src/pro/poloniexfutures.js +6 -2
  57. package/js/src/pro/woofipro.js +1 -1
  58. package/js/src/woo.d.ts +5 -1
  59. package/js/src/woo.js +313 -81
  60. package/js/src/xt.d.ts +3 -3
  61. package/package.json +1 -1
@@ -161,6 +161,9 @@ class cryptocom extends cryptocom$1 {
161
161
  'public/get-expired-settlement-price': 10 / 3,
162
162
  'public/get-insurance': 1,
163
163
  },
164
+ 'post': {
165
+ 'public/staking/get-conversion-rate': 2,
166
+ },
164
167
  },
165
168
  'private': {
166
169
  'post': {
@@ -190,6 +193,16 @@ class cryptocom extends cryptocom$1 {
190
193
  'private/get-accounts': 10 / 3,
191
194
  'private/get-withdrawal-history': 10 / 3,
192
195
  'private/get-deposit-history': 10 / 3,
196
+ 'private/staking/stake': 2,
197
+ 'private/staking/unstake': 2,
198
+ 'private/staking/get-staking-position': 2,
199
+ 'private/staking/get-staking-instruments': 2,
200
+ 'private/staking/get-open-stake': 2,
201
+ 'private/staking/get-stake-history': 2,
202
+ 'private/staking/get-reward-history': 2,
203
+ 'private/staking/convert': 2,
204
+ 'private/staking/get-open-convert': 2,
205
+ 'private/staking/get-convert-history': 2,
193
206
  },
194
207
  },
195
208
  },
@@ -815,6 +828,9 @@ class cryptocom extends cryptocom$1 {
815
828
  'timeframe': this.safeString(this.timeframes, timeframe, timeframe),
816
829
  };
817
830
  if (limit !== undefined) {
831
+ if (limit > 300) {
832
+ limit = 300;
833
+ }
818
834
  request['count'] = limit;
819
835
  }
820
836
  const now = this.microseconds();
@@ -822,9 +838,9 @@ class cryptocom extends cryptocom$1 {
822
838
  const until = this.safeInteger(params, 'until', now);
823
839
  params = this.omit(params, ['until']);
824
840
  if (since !== undefined) {
825
- request['start_ts'] = since;
841
+ request['start_ts'] = since - duration * 1000;
826
842
  if (limit !== undefined) {
827
- request['end_ts'] = this.sum(since, duration * (limit + 1) * 1000) - 1;
843
+ request['end_ts'] = this.sum(since, duration * limit * 1000);
828
844
  }
829
845
  else {
830
846
  request['end_ts'] = until;
@@ -4,6 +4,7 @@ var mercado$1 = require('./abstract/mercado.js');
4
4
  var errors = require('./base/errors.js');
5
5
  var number = require('./base/functions/number.js');
6
6
  var sha512 = require('./static_dependencies/noble-hashes/sha512.js');
7
+ var Precise = require('./base/Precise.js');
7
8
 
8
9
  // ---------------------------------------------------------------------------
9
10
  // ---------------------------------------------------------------------------
@@ -460,7 +461,10 @@ class mercado extends mercado$1 {
460
461
  if (price === undefined) {
461
462
  throw new errors.InvalidOrder(this.id + ' createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount');
462
463
  }
463
- request['cost'] = this.priceToPrecision(market['symbol'], amount * price);
464
+ const amountString = this.numberToString(amount);
465
+ const priceString = this.numberToString(price);
466
+ const cost = this.parseToNumeric(Precise["default"].stringMul(amountString, priceString));
467
+ request['cost'] = this.priceToPrecision(market['symbol'], cost);
464
468
  }
465
469
  else {
466
470
  request['quantity'] = this.amountToPrecision(market['symbol'], amount);
@@ -24,7 +24,7 @@ class binance extends binance$1 {
24
24
  'watchBidsAsks': true,
25
25
  'watchMyTrades': true,
26
26
  'watchOHLCV': true,
27
- 'watchOHLCVForSymbols': false,
27
+ 'watchOHLCVForSymbols': true,
28
28
  'watchOrderBook': true,
29
29
  'watchOrderBookForSymbols': true,
30
30
  'watchOrders': true,
@@ -127,6 +127,7 @@ class binance extends binance$1 {
127
127
  },
128
128
  'watchOrderBook': {
129
129
  'maxRetries': 3,
130
+ 'checksum': true,
130
131
  },
131
132
  'watchBalance': {
132
133
  'fetchBalanceSnapshot': false,
@@ -854,10 +855,10 @@ class binance extends binance$1 {
854
855
  }
855
856
  }
856
857
  else {
857
- const checksum = this.safeBool(this.options, 'checksum', true);
858
+ const checksum = this.handleOption('watchOrderBook', 'checksum', true);
858
859
  if (checksum) {
859
860
  // todo: client.reject from handleOrderBookMessage properly
860
- throw new errors.InvalidNonce(this.id + ' handleOrderBook received an out-of-order nonce');
861
+ throw new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
861
862
  }
862
863
  }
863
864
  }
@@ -875,10 +876,10 @@ class binance extends binance$1 {
875
876
  }
876
877
  }
877
878
  else {
878
- const checksum = this.safeBool(this.options, 'checksum', true);
879
+ const checksum = this.handleOption('watchOrderBook', 'checksum', true);
879
880
  if (checksum) {
880
881
  // todo: client.reject from handleOrderBookMessage properly
881
- throw new errors.InvalidNonce(this.id + ' handleOrderBook received an out-of-order nonce');
882
+ throw new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
882
883
  }
883
884
  }
884
885
  }
@@ -1188,40 +1189,63 @@ class binance extends binance$1 {
1188
1189
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1189
1190
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
1190
1191
  */
1192
+ params['callerMethodName'] = 'watchOHLCV';
1193
+ const result = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, params);
1194
+ return result[symbol][timeframe];
1195
+ }
1196
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
1197
+ /**
1198
+ * @method
1199
+ * @name binance#watchOHLCVForSymbols
1200
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1201
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
1202
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
1203
+ * @param {int} [limit] the maximum amount of candles to fetch
1204
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1205
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
1206
+ */
1191
1207
  await this.loadMarkets();
1192
- const market = this.market(symbol);
1193
- let marketId = market['lowercaseId'];
1194
- const interval = this.safeString(this.timeframes, timeframe, timeframe);
1195
- const options = this.safeValue(this.options, 'watchOHLCV', {});
1196
- const nameOption = this.safeString(options, 'name', 'kline');
1197
- const name = this.safeString(params, 'name', nameOption);
1198
- if (name === 'indexPriceKline') {
1199
- marketId = marketId.replace('_perp', '');
1200
- // weird behavior for index price kline we can't use the perp suffix
1201
- }
1202
- params = this.omit(params, 'name');
1203
- const messageHash = marketId + '@' + name + '_' + interval;
1204
- let type = market['type'];
1205
- if (market['contract']) {
1206
- type = market['linear'] ? 'future' : 'delivery';
1207
- }
1208
- const url = this.urls['api']['ws'][type] + '/' + this.stream(type, messageHash);
1208
+ let klineType = undefined;
1209
+ [klineType, params] = this.handleParamString2(params, 'channel', 'name', 'kline');
1210
+ const symbols = this.getListFromObjectValues(symbolsAndTimeframes, 0);
1211
+ const marketSymbols = this.marketSymbols(symbols, undefined, false, false, true);
1212
+ const firstMarket = this.market(marketSymbols[0]);
1213
+ let type = firstMarket['type'];
1214
+ if (firstMarket['contract']) {
1215
+ type = firstMarket['linear'] ? 'future' : 'delivery';
1216
+ }
1217
+ const rawHashes = [];
1218
+ const messageHashes = [];
1219
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
1220
+ const symAndTf = symbolsAndTimeframes[i];
1221
+ const symbolString = symAndTf[0];
1222
+ const timeframeString = symAndTf[1];
1223
+ const interval = this.safeString(this.timeframes, timeframeString, timeframeString);
1224
+ const market = this.market(symbolString);
1225
+ let marketId = market['lowercaseId'];
1226
+ if (klineType === 'indexPriceKline') {
1227
+ // weird behavior for index price kline we can't use the perp suffix
1228
+ marketId = marketId.replace('_perp', '');
1229
+ }
1230
+ rawHashes.push(marketId + '@' + klineType + '_' + interval);
1231
+ messageHashes.push('ohlcv::' + symbolString + '::' + timeframeString);
1232
+ }
1233
+ const url = this.urls['api']['ws'][type] + '/' + this.stream(type, 'multipleOHLCV');
1209
1234
  const requestId = this.requestId(url);
1210
1235
  const request = {
1211
1236
  'method': 'SUBSCRIBE',
1212
- 'params': [
1213
- messageHash,
1214
- ],
1237
+ 'params': rawHashes,
1215
1238
  'id': requestId,
1216
1239
  };
1217
1240
  const subscribe = {
1218
1241
  'id': requestId,
1219
1242
  };
1220
- const ohlcv = await this.watch(url, messageHash, this.extend(request, params), messageHash, subscribe);
1243
+ const [symbol, timeframe, candles] = await this.watchMultiple(url, messageHashes, this.extend(request, params), messageHashes, subscribe);
1221
1244
  if (this.newUpdates) {
1222
- limit = ohlcv.getLimit(symbol, limit);
1245
+ limit = candles.getLimit(symbol, limit);
1223
1246
  }
1224
- return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
1247
+ const filtered = this.filterBySinceLimit(candles, since, limit, 0, true);
1248
+ return this.createOHLCVObject(symbol, timeframe, filtered);
1225
1249
  }
1226
1250
  handleOHLCV(client, message) {
1227
1251
  //
@@ -1262,11 +1286,9 @@ class binance extends binance$1 {
1262
1286
  // indexPriceKline doesn't have the _PERP suffix
1263
1287
  marketId = this.safeString(message, 'ps');
1264
1288
  }
1265
- const lowercaseMarketId = marketId.toLowerCase();
1266
1289
  const interval = this.safeString(kline, 'i');
1267
1290
  // use a reverse lookup in a static map instead
1268
- const timeframe = this.findTimeframe(interval);
1269
- const messageHash = lowercaseMarketId + '@' + event + '_' + interval;
1291
+ const unifiedTimeframe = this.findTimeframe(interval);
1270
1292
  const parsed = [
1271
1293
  this.safeInteger(kline, 't'),
1272
1294
  this.safeFloat(kline, 'o'),
@@ -1278,15 +1300,17 @@ class binance extends binance$1 {
1278
1300
  const isSpot = ((client.url.indexOf('/stream') > -1) || (client.url.indexOf('/testnet.binance') > -1));
1279
1301
  const marketType = (isSpot) ? 'spot' : 'contract';
1280
1302
  const symbol = this.safeSymbol(marketId, undefined, undefined, marketType);
1303
+ const messageHash = 'ohlcv::' + symbol + '::' + unifiedTimeframe;
1281
1304
  this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
1282
- let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
1305
+ let stored = this.safeValue(this.ohlcvs[symbol], unifiedTimeframe);
1283
1306
  if (stored === undefined) {
1284
1307
  const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
1285
1308
  stored = new Cache.ArrayCacheByTimestamp(limit);
1286
- this.ohlcvs[symbol][timeframe] = stored;
1309
+ this.ohlcvs[symbol][unifiedTimeframe] = stored;
1287
1310
  }
1288
1311
  stored.append(parsed);
1289
- client.resolve(stored, messageHash);
1312
+ const resolveData = [symbol, unifiedTimeframe, stored];
1313
+ client.resolve(resolveData, messageHash);
1290
1314
  }
1291
1315
  async fetchTickerWs(symbol, params = {}) {
1292
1316
  /**
@@ -34,9 +34,9 @@ class bitfinex2 extends bitfinex2$1 {
34
34
  'watchOrderBook': {
35
35
  'prec': 'P0',
36
36
  'freq': 'F0',
37
+ 'checksum': true,
37
38
  },
38
39
  'ordersLimit': 1000,
39
- 'checksum': true,
40
40
  },
41
41
  });
42
42
  }
@@ -681,10 +681,13 @@ class bitfinex2 extends bitfinex2$1 {
681
681
  const localChecksum = this.crc32(payload, true);
682
682
  const responseChecksum = this.safeInteger(message, 2);
683
683
  if (responseChecksum !== localChecksum) {
684
- const error = new errors.InvalidNonce(this.id + ' invalid checksum');
685
684
  delete client.subscriptions[messageHash];
686
685
  delete this.orderbooks[symbol];
687
- client.reject(error, messageHash);
686
+ const checksum = this.handleOption('watchOrderBook', 'checksum', true);
687
+ if (checksum) {
688
+ const error = new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
689
+ client.reject(error, messageHash);
690
+ }
688
691
  }
689
692
  }
690
693
  async watchBalance(params = {}) {
@@ -62,6 +62,9 @@ class bitget extends bitget$1 {
62
62
  '1d': '1D',
63
63
  '1w': '1W',
64
64
  },
65
+ 'watchOrderBook': {
66
+ 'checksum': true,
67
+ },
65
68
  },
66
69
  'streaming': {
67
70
  'ping': this.ping,
@@ -559,9 +562,9 @@ class bitget extends bitget$1 {
559
562
  const calculatedChecksum = this.crc32(payload, true);
560
563
  const responseChecksum = this.safeInteger(rawOrderBook, 'checksum');
561
564
  if (calculatedChecksum !== responseChecksum) {
562
- const error = new errors.InvalidNonce(this.id + ' invalid checksum');
563
565
  delete client.subscriptions[messageHash];
564
566
  delete this.orderbooks[symbol];
567
+ const error = new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
565
568
  client.reject(error, messageHash);
566
569
  return;
567
570
  }
@@ -500,7 +500,7 @@ class bitvavo extends bitvavo$1 {
500
500
  * @param {int} [since] the earliest time in ms to fetch trades for
501
501
  * @param {int} [limit] the maximum number of trade structures to retrieve
502
502
  * @param {object} [params] extra parameters specific to the exchange API endpoint
503
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=ortradeder-structure
503
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
504
504
  */
505
505
  if (symbol === undefined) {
506
506
  throw new errors.ArgumentsRequired(this.id + ' watchMyTrades() requires a symbol argument');
@@ -28,7 +28,7 @@ class bybit extends bybit$1 {
28
28
  'watchMyLiquidationsForSymbols': false,
29
29
  'watchMyTrades': true,
30
30
  'watchOHLCV': true,
31
- 'watchOHLCVForSymbols': false,
31
+ 'watchOHLCVForSymbols': true,
32
32
  'watchOrderBook': true,
33
33
  'watchOrderBookForSymbols': true,
34
34
  'watchOrders': true,
@@ -530,20 +530,46 @@ class bybit extends bybit$1 {
530
530
  * @param {object} [params] extra parameters specific to the exchange API endpoint
531
531
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
532
532
  */
533
+ params['callerMethodName'] = 'watchOHLCV';
534
+ const result = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, params);
535
+ return result[symbol][timeframe];
536
+ }
537
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
538
+ /**
539
+ * @method
540
+ * @name bybit#watchOHLCVForSymbols
541
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
542
+ * @see https://bybit-exchange.github.io/docs/v5/websocket/public/kline
543
+ * @see https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
544
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
545
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
546
+ * @param {int} [limit] the maximum amount of candles to fetch
547
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
548
+ * @returns {object} A list of candles ordered as timestamp, open, high, low, close, volume
549
+ */
533
550
  await this.loadMarkets();
534
- const market = this.market(symbol);
535
- symbol = market['symbol'];
536
- const url = await this.getUrlByMarketType(symbol, false, 'watchOHLCV', params);
537
- params = this.cleanParams(params);
538
- let ohlcv = undefined;
539
- const timeframeId = this.safeString(this.timeframes, timeframe, timeframe);
540
- const topics = ['kline.' + timeframeId + '.' + market['id']];
541
- const messageHash = 'kline' + ':' + timeframeId + ':' + symbol;
542
- ohlcv = await this.watchTopics(url, [messageHash], topics, params);
551
+ const symbols = this.getListFromObjectValues(symbolsAndTimeframes, 0);
552
+ const marketSymbols = this.marketSymbols(symbols, undefined, false, true, true);
553
+ const firstSymbol = marketSymbols[0];
554
+ const url = await this.getUrlByMarketType(firstSymbol, false, 'watchOHLCVForSymbols', params);
555
+ const rawHashes = [];
556
+ const messageHashes = [];
557
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
558
+ const data = symbolsAndTimeframes[i];
559
+ let symbolString = this.safeString(data, 0);
560
+ const market = this.market(symbolString);
561
+ symbolString = market['symbol'];
562
+ const unfiedTimeframe = this.safeString(data, 1);
563
+ const timeframeId = this.safeString(this.timeframes, unfiedTimeframe, unfiedTimeframe);
564
+ rawHashes.push('kline.' + timeframeId + '.' + market['id']);
565
+ messageHashes.push('ohlcv::' + symbolString + '::' + unfiedTimeframe);
566
+ }
567
+ const [symbol, timeframe, stored] = await this.watchTopics(url, messageHashes, rawHashes, params);
543
568
  if (this.newUpdates) {
544
- limit = ohlcv.getLimit(symbol, limit);
569
+ limit = stored.getLimit(symbol, limit);
545
570
  }
546
- return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
571
+ const filtered = this.filterBySinceLimit(stored, since, limit, 0, true);
572
+ return this.createOHLCVObject(symbol, timeframe, filtered);
547
573
  }
548
574
  handleOHLCV(client, message) {
549
575
  //
@@ -583,18 +609,18 @@ class bybit extends bybit$1 {
583
609
  if (ohlcvsByTimeframe === undefined) {
584
610
  this.ohlcvs[symbol] = {};
585
611
  }
586
- let stored = this.safeValue(ohlcvsByTimeframe, timeframe);
587
- if (stored === undefined) {
612
+ if (this.safeValue(ohlcvsByTimeframe, timeframe) === undefined) {
588
613
  const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
589
- stored = new Cache.ArrayCacheByTimestamp(limit);
590
- this.ohlcvs[symbol][timeframe] = stored;
614
+ this.ohlcvs[symbol][timeframe] = new Cache.ArrayCacheByTimestamp(limit);
591
615
  }
616
+ const stored = this.ohlcvs[symbol][timeframe];
592
617
  for (let i = 0; i < data.length; i++) {
593
618
  const parsed = this.parseWsOHLCV(data[i]);
594
619
  stored.append(parsed);
595
620
  }
596
- const messageHash = 'kline' + ':' + timeframeId + ':' + symbol;
597
- client.resolve(stored, messageHash);
621
+ const messageHash = 'ohlcv::' + symbol + '::' + timeframe;
622
+ const resolveData = [symbol, timeframe, stored];
623
+ client.resolve(resolveData, messageHash);
598
624
  }
599
625
  parseWsOHLCV(ohlcv, market = undefined) {
600
626
  //
@@ -44,6 +44,9 @@ class cryptocom extends cryptocom$1 {
44
44
  'fetchPositionsSnapshot': true,
45
45
  'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
46
46
  },
47
+ 'watchOrderBook': {
48
+ 'checksum': true,
49
+ },
47
50
  },
48
51
  'streaming': {},
49
52
  });
@@ -217,7 +220,10 @@ class cryptocom extends cryptocom$1 {
217
220
  const previousNonce = this.safeInteger(data, 'pu');
218
221
  const currentNonce = orderbook['nonce'];
219
222
  if (currentNonce !== previousNonce) {
220
- throw new errors.InvalidNonce(this.id + ' watchOrderBook() ' + symbol + ' ' + previousNonce + ' != ' + nonce);
223
+ const checksum = this.handleOption('watchOrderBook', 'checksum', true);
224
+ if (checksum) {
225
+ throw new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
226
+ }
221
227
  }
222
228
  }
223
229
  this.handleDeltas(orderbook['asks'], this.safeValue(books, 'asks', []));
@@ -94,6 +94,7 @@ class gate extends gate$1 {
94
94
  'interval': '100ms',
95
95
  'snapshotDelay': 10,
96
96
  'snapshotMaxRetries': 3,
97
+ 'checksum': true,
97
98
  },
98
99
  'watchBalance': {
99
100
  'settle': 'usdt',
@@ -479,10 +480,13 @@ class gate extends gate$1 {
479
480
  this.handleDelta(storedOrderBook, delta);
480
481
  }
481
482
  else {
482
- const error = new errors.InvalidNonce(this.id + ' orderbook update has a nonce bigger than u');
483
483
  delete client.subscriptions[messageHash];
484
484
  delete this.orderbooks[symbol];
485
- client.reject(error, messageHash);
485
+ const checksum = this.handleOption('watchOrderBook', 'checksum', true);
486
+ if (checksum) {
487
+ const error = new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
488
+ client.reject(error, messageHash);
489
+ }
486
490
  }
487
491
  client.resolve(storedOrderBook, messageHash);
488
492
  }
@@ -97,6 +97,7 @@ class htx extends htx$1 {
97
97
  'api': 'api',
98
98
  'watchOrderBook': {
99
99
  'maxRetries': 3,
100
+ 'checksum': true,
100
101
  },
101
102
  'ws': {
102
103
  'gunzip': true,
@@ -568,7 +569,10 @@ class htx extends htx$1 {
568
569
  orderbook['nonce'] = version;
569
570
  }
570
571
  if ((prevSeqNum !== undefined) && prevSeqNum > orderbook['nonce']) {
571
- throw new errors.InvalidNonce(this.id + ' watchOrderBook() received a mesage out of order');
572
+ const checksum = this.handleOption('watchOrderBook', 'checksum', true);
573
+ if (checksum) {
574
+ throw new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
575
+ }
572
576
  }
573
577
  const spotConditon = market['spot'] && (prevSeqNum === orderbook['nonce']);
574
578
  const nonSpotCondition = market['contract'] && (version - 1 === orderbook['nonce']);
@@ -26,7 +26,9 @@ class independentreserve extends independentreserve$1 {
26
26
  },
27
27
  },
28
28
  'options': {
29
- 'checksum': false, // TODO: currently only working for snapshot
29
+ 'watchOrderBook': {
30
+ 'checksum': true, // TODO: currently only working for snapshot
31
+ },
30
32
  },
31
33
  'streaming': {},
32
34
  'exceptions': {},
@@ -196,7 +198,7 @@ class independentreserve extends independentreserve$1 {
196
198
  orderbook['timestamp'] = timestamp;
197
199
  orderbook['datetime'] = this.iso8601(timestamp);
198
200
  }
199
- const checksum = this.safeBool(this.options, 'checksum', true);
201
+ const checksum = this.handleOption('watchOrderBook', 'checksum', true);
200
202
  if (checksum && receivedSnapshot) {
201
203
  const storedAsks = orderbook['asks'];
202
204
  const storedBids = orderbook['bids'];
@@ -216,7 +218,7 @@ class independentreserve extends independentreserve$1 {
216
218
  const calculatedChecksum = this.crc32(payload, true);
217
219
  const responseChecksum = this.safeInteger(orderBook, 'Crc32');
218
220
  if (calculatedChecksum !== responseChecksum) {
219
- const error = new errors.InvalidNonce(this.id + ' invalid checksum');
221
+ const error = new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
220
222
  delete client.subscriptions[messageHash];
221
223
  delete this.orderbooks[symbol];
222
224
  client.reject(error, messageHash);
@@ -12,7 +12,7 @@ class kraken extends kraken$1 {
12
12
  return this.deepExtend(super.describe(), {
13
13
  'has': {
14
14
  'ws': true,
15
- 'watchBalance': false,
15
+ 'watchBalance': true,
16
16
  'watchMyTrades': true,
17
17
  'watchOHLCV': true,
18
18
  'watchOrderBook': true,
@@ -35,6 +35,7 @@ class kraken extends kraken$1 {
35
35
  'ws': {
36
36
  'public': 'wss://ws.kraken.com',
37
37
  'private': 'wss://ws-auth.kraken.com',
38
+ 'privateV2': 'wss://ws-auth.kraken.com/v2',
38
39
  'beta': 'wss://beta-ws.kraken.com',
39
40
  'beta-private': 'wss://beta-ws-auth.kraken.com',
40
41
  },
@@ -48,7 +49,9 @@ class kraken extends kraken$1 {
48
49
  'OHLCVLimit': 1000,
49
50
  'ordersLimit': 1000,
50
51
  'symbolsByOrderId': {},
51
- 'checksum': true,
52
+ 'watchOrderBook': {
53
+ 'checksum': true,
54
+ },
52
55
  },
53
56
  'exceptions': {
54
57
  'ws': {
@@ -746,7 +749,7 @@ class kraken extends kraken$1 {
746
749
  }
747
750
  // don't remove this line or I will poop on your face
748
751
  orderbook.limit();
749
- const checksum = this.safeBool(this.options, 'checksum', true);
752
+ const checksum = this.handleOption('watchOrderBook', 'checksum', true);
750
753
  if (checksum) {
751
754
  const priceString = this.safeString(example, 0);
752
755
  const amountString = this.safeString(example, 1);
@@ -768,7 +771,7 @@ class kraken extends kraken$1 {
768
771
  const payload = payloadArray.join('');
769
772
  const localChecksum = this.crc32(payload, false);
770
773
  if (localChecksum !== c) {
771
- const error = new errors.InvalidNonce(this.id + ' invalid checksum');
774
+ const error = new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
772
775
  delete client.subscriptions[messageHash];
773
776
  delete this.orderbooks[symbol];
774
777
  client.reject(error, messageHash);
@@ -1326,6 +1329,71 @@ class kraken extends kraken$1 {
1326
1329
  const url = this.urls['api']['ws']['public'];
1327
1330
  return await this.watchMultiple(url, messageHashes, this.deepExtend(request, params), messageHashes, subscriptionArgs);
1328
1331
  }
1332
+ async watchBalance(params = {}) {
1333
+ /**
1334
+ * @method
1335
+ * @name kraken#watchBalance
1336
+ * @description watch balance and get the amount of funds available for trading or funds locked in orders
1337
+ * @see https://docs.kraken.com/api/docs/websocket-v2/balances
1338
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1339
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1340
+ */
1341
+ await this.loadMarkets();
1342
+ const token = await this.authenticate();
1343
+ const messageHash = 'balances';
1344
+ const url = this.urls['api']['ws']['privateV2'];
1345
+ const requestId = this.requestId();
1346
+ const subscribe = {
1347
+ 'method': 'subscribe',
1348
+ 'req_id': requestId,
1349
+ 'params': {
1350
+ 'channel': 'balances',
1351
+ 'token': token,
1352
+ },
1353
+ };
1354
+ const request = this.deepExtend(subscribe, params);
1355
+ return await this.watch(url, messageHash, request, messageHash);
1356
+ }
1357
+ handleBalance(client, message) {
1358
+ //
1359
+ // {
1360
+ // "channel": "balances",
1361
+ // "data": [
1362
+ // {
1363
+ // "asset": "BTC",
1364
+ // "asset_class": "currency",
1365
+ // "balance": 1.2,
1366
+ // "wallets": [
1367
+ // {
1368
+ // "type": "spot",
1369
+ // "id": "main",
1370
+ // "balance": 1.2
1371
+ // }
1372
+ // ]
1373
+ // }
1374
+ // ],
1375
+ // "type": "snapshot",
1376
+ // "sequence": 1
1377
+ // }
1378
+ //
1379
+ const data = this.safeList(message, 'data', []);
1380
+ const result = { 'info': message };
1381
+ for (let i = 0; i < data.length; i++) {
1382
+ const currencyId = this.safeString(data[i], 'asset');
1383
+ const code = this.safeCurrencyCode(currencyId);
1384
+ const account = this.account();
1385
+ const eq = this.safeString(data[i], 'balance');
1386
+ account['total'] = eq;
1387
+ result[code] = account;
1388
+ }
1389
+ const type = 'spot';
1390
+ const balance = this.safeBalance(result);
1391
+ const oldBalance = this.safeValue(this.balance, type, {});
1392
+ const newBalance = this.deepExtend(oldBalance, balance);
1393
+ this.balance[type] = this.safeBalance(newBalance);
1394
+ const channel = this.safeString(message, 'channel');
1395
+ client.resolve(this.balance[type], channel);
1396
+ }
1329
1397
  getMessageHash(unifiedElementName, subChannelName = undefined, symbol = undefined) {
1330
1398
  // unifiedElementName can be : orderbook, trade, ticker, bidask ...
1331
1399
  // subChannelName only applies to channel that needs specific variation (i.e. depth_50, depth_100..) to be selected
@@ -1429,6 +1497,16 @@ class kraken extends kraken$1 {
1429
1497
  }
1430
1498
  }
1431
1499
  else {
1500
+ const channel = this.safeString(message, 'channel');
1501
+ if (channel !== undefined) {
1502
+ const methods = {
1503
+ 'balances': this.handleBalance,
1504
+ };
1505
+ const method = this.safeValue(methods, channel);
1506
+ if (method !== undefined) {
1507
+ method.call(this, client, message);
1508
+ }
1509
+ }
1432
1510
  if (this.handleErrorMessage(client, message)) {
1433
1511
  const event = this.safeString(message, 'event');
1434
1512
  const methods = {