ccxt 4.1.47 → 4.1.49

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 (114) hide show
  1. package/README.md +124 -124
  2. package/dist/ccxt.browser.js +670 -460
  3. package/dist/ccxt.browser.min.js +3 -3
  4. package/dist/cjs/ccxt.js +6 -1
  5. package/dist/cjs/src/abstract/htx.js +9 -0
  6. package/dist/cjs/src/binance.js +2 -0
  7. package/dist/cjs/src/bitmart.js +183 -62
  8. package/dist/cjs/src/coinex.js +67 -18
  9. package/dist/cjs/src/htx.js +8505 -0
  10. package/dist/cjs/src/huobi.js +5 -8503
  11. package/dist/cjs/src/kraken.js +0 -4
  12. package/dist/cjs/src/mexc.js +21 -21
  13. package/dist/cjs/src/pro/htx.js +2356 -0
  14. package/dist/cjs/src/pro/huobi.js +5 -2345
  15. package/dist/cjs/src/timex.js +1 -1
  16. package/js/ccxt.d.ts +8 -2
  17. package/js/ccxt.js +6 -2
  18. package/js/src/abstract/binance.d.ts +2 -0
  19. package/js/src/abstract/binancecoinm.d.ts +2 -0
  20. package/js/src/abstract/binanceus.d.ts +2 -0
  21. package/js/src/abstract/binanceusdm.d.ts +2 -0
  22. package/js/src/abstract/htx.d.ts +544 -0
  23. package/js/src/abstract/htx.js +11 -0
  24. package/js/src/abstract/huobi.d.ts +4 -4
  25. package/js/src/abstract/huobi.js +3 -3
  26. package/js/src/ace.d.ts +2 -2
  27. package/js/src/ascendex.d.ts +2 -2
  28. package/js/src/base/Exchange.d.ts +2 -2
  29. package/js/src/base/types.d.ts +0 -1
  30. package/js/src/bigone.d.ts +2 -2
  31. package/js/src/binance.d.ts +3 -56
  32. package/js/src/binance.js +2 -0
  33. package/js/src/bingx.d.ts +3 -55
  34. package/js/src/bitbns.d.ts +2 -2
  35. package/js/src/bitfinex.d.ts +2 -2
  36. package/js/src/bitfinex2.d.ts +2 -2
  37. package/js/src/bitget.d.ts +3 -53
  38. package/js/src/bithumb.d.ts +2 -2
  39. package/js/src/bitmart.d.ts +4 -2
  40. package/js/src/bitmart.js +183 -62
  41. package/js/src/bitmex.d.ts +2 -2
  42. package/js/src/bitopro.d.ts +2 -2
  43. package/js/src/bitpanda.d.ts +2 -2
  44. package/js/src/bitrue.d.ts +2 -2
  45. package/js/src/bitstamp.d.ts +2 -2
  46. package/js/src/bittrex.d.ts +2 -2
  47. package/js/src/bitvavo.d.ts +2 -2
  48. package/js/src/blockchaincom.d.ts +2 -2
  49. package/js/src/btcalpha.d.ts +2 -2
  50. package/js/src/btcturk.d.ts +2 -2
  51. package/js/src/bybit.d.ts +2 -2
  52. package/js/src/cex.d.ts +2 -2
  53. package/js/src/coinbase.d.ts +2 -2
  54. package/js/src/coinbasepro.d.ts +2 -2
  55. package/js/src/coinex.d.ts +2 -2
  56. package/js/src/coinex.js +67 -18
  57. package/js/src/coinfalcon.d.ts +2 -2
  58. package/js/src/coinlist.d.ts +2 -2
  59. package/js/src/coinone.d.ts +2 -2
  60. package/js/src/coinsph.d.ts +2 -2
  61. package/js/src/coinspot.d.ts +2 -2
  62. package/js/src/cryptocom.d.ts +2 -2
  63. package/js/src/currencycom.d.ts +2 -2
  64. package/js/src/delta.d.ts +2 -2
  65. package/js/src/deribit.d.ts +2 -2
  66. package/js/src/digifinex.d.ts +2 -2
  67. package/js/src/exmo.d.ts +2 -2
  68. package/js/src/gate.d.ts +2 -2
  69. package/js/src/gemini.d.ts +3 -51
  70. package/js/src/hitbtc.d.ts +2 -2
  71. package/js/src/hollaex.d.ts +2 -2
  72. package/js/src/htx.d.ts +257 -0
  73. package/js/src/htx.js +8506 -0
  74. package/js/src/huobi.d.ts +2 -255
  75. package/js/src/huobi.js +5 -8503
  76. package/js/src/huobijp.d.ts +2 -2
  77. package/js/src/idex.d.ts +2 -2
  78. package/js/src/indodax.d.ts +2 -2
  79. package/js/src/kraken.d.ts +2 -2
  80. package/js/src/kraken.js +0 -4
  81. package/js/src/krakenfutures.d.ts +2 -2
  82. package/js/src/kucoin.d.ts +2 -2
  83. package/js/src/kuna.d.ts +2 -2
  84. package/js/src/latoken.d.ts +2 -2
  85. package/js/src/lbank.d.ts +2 -2
  86. package/js/src/lbank2.d.ts +2 -2
  87. package/js/src/luno.d.ts +2 -2
  88. package/js/src/lykke.d.ts +2 -2
  89. package/js/src/mexc.d.ts +2 -2
  90. package/js/src/mexc.js +21 -21
  91. package/js/src/novadax.d.ts +2 -2
  92. package/js/src/oceanex.d.ts +2 -2
  93. package/js/src/okcoin.d.ts +3 -3
  94. package/js/src/okx.d.ts +3 -3
  95. package/js/src/phemex.d.ts +2 -2
  96. package/js/src/poloniex.d.ts +2 -2
  97. package/js/src/poloniexfutures.d.ts +2 -2
  98. package/js/src/pro/htx.d.ts +45 -0
  99. package/js/src/pro/htx.js +2357 -0
  100. package/js/src/pro/huobi.d.ts +2 -43
  101. package/js/src/pro/huobi.js +5 -2345
  102. package/js/src/probit.d.ts +2 -2
  103. package/js/src/tidex.d.ts +2 -2
  104. package/js/src/timex.d.ts +3 -53
  105. package/js/src/timex.js +1 -1
  106. package/js/src/tokocrypto.d.ts +2 -2
  107. package/js/src/upbit.d.ts +2 -2
  108. package/js/src/wavesexchange.d.ts +2 -2
  109. package/js/src/wazirx.d.ts +2 -2
  110. package/js/src/whitebit.d.ts +2 -2
  111. package/js/src/yobit.d.ts +2 -2
  112. package/js/src/zonda.d.ts +2 -2
  113. package/package.json +1 -1
  114. package/skip-tests.json +4 -4
@@ -1,2356 +1,16 @@
1
1
  'use strict';
2
2
 
3
- var huobi$1 = require('../huobi.js');
4
- var errors = require('../base/errors.js');
5
- var Cache = require('../base/ws/Cache.js');
6
- var sha256 = require('../static_dependencies/noble-hashes/sha256.js');
3
+ var htx = require('./htx.js');
7
4
 
8
5
  // ---------------------------------------------------------------------------
9
- // ---------------------------------------------------------------------------
10
- class huobi extends huobi$1 {
6
+ // ---------------------------------------------------------------------------
7
+ class huobi extends htx {
11
8
  describe() {
12
9
  return this.deepExtend(super.describe(), {
13
- 'has': {
14
- 'ws': true,
15
- 'watchOrderBook': true,
16
- 'watchOrders': true,
17
- 'watchTickers': false,
18
- 'watchTicker': true,
19
- 'watchTrades': true,
20
- 'watchMyTrades': true,
21
- 'watchBalance': true,
22
- 'watchOHLCV': true,
23
- },
24
- 'urls': {
25
- 'api': {
26
- 'ws': {
27
- 'api': {
28
- 'spot': {
29
- 'public': 'wss://{hostname}/ws',
30
- 'private': 'wss://{hostname}/ws/v2',
31
- },
32
- 'future': {
33
- 'linear': {
34
- 'public': 'wss://api.hbdm.com/linear-swap-ws',
35
- 'private': 'wss://api.hbdm.com/linear-swap-notification',
36
- },
37
- 'inverse': {
38
- 'public': 'wss://api.hbdm.com/ws',
39
- 'private': 'wss://api.hbdm.com/notification',
40
- },
41
- },
42
- 'swap': {
43
- 'inverse': {
44
- 'public': 'wss://api.hbdm.com/swap-ws',
45
- 'private': 'wss://api.hbdm.com/swap-notification',
46
- },
47
- 'linear': {
48
- 'public': 'wss://api.hbdm.com/linear-swap-ws',
49
- 'private': 'wss://api.hbdm.com/linear-swap-notification',
50
- },
51
- },
52
- },
53
- // these settings work faster for clients hosted on AWS
54
- 'api-aws': {
55
- 'spot': {
56
- 'public': 'wss://api-aws.huobi.pro/ws',
57
- 'private': 'wss://api-aws.huobi.pro/ws/v2',
58
- },
59
- 'future': {
60
- 'linear': {
61
- 'public': 'wss://api.hbdm.vn/linear-swap-ws',
62
- 'private': 'wss://api.hbdm.vn/linear-swap-notification',
63
- },
64
- 'inverse': {
65
- 'public': 'wss://api.hbdm.vn/ws',
66
- 'private': 'wss://api.hbdm.vn/notification',
67
- },
68
- },
69
- 'swap': {
70
- 'linear': {
71
- 'public': 'wss://api.hbdm.vn/linear-swap-ws',
72
- 'private': 'wss://api.hbdm.vn/linear-swap-notification',
73
- },
74
- 'inverse': {
75
- 'public': 'wss://api.hbdm.vn/swap-ws',
76
- 'private': 'wss://api.hbdm.vn/swap-notification',
77
- },
78
- },
79
- },
80
- },
81
- },
82
- },
83
- 'options': {
84
- 'tradesLimit': 1000,
85
- 'OHLCVLimit': 1000,
86
- 'api': 'api',
87
- 'watchOrderBook': {
88
- 'maxRetries': 3,
89
- },
90
- 'ws': {
91
- 'gunzip': true,
92
- },
93
- 'watchTicker': {
94
- 'name': 'market.{marketId}.detail', // 'market.{marketId}.bbo' or 'market.{marketId}.ticker'
95
- },
96
- },
97
- 'exceptions': {
98
- 'ws': {
99
- 'exact': {
100
- 'bad-request': errors.BadRequest,
101
- '2002': errors.AuthenticationError,
102
- '2021': errors.BadRequest,
103
- '2001': errors.BadSymbol,
104
- '2011': errors.BadSymbol,
105
- '2040': errors.BadRequest,
106
- '4007': errors.BadRequest, // { op: 'sub', cid: '1', topic: 'accounts_unify.USDT', 'err-code': 4007, 'err-msg': 'Non - single account user is not available, please check through the cross and isolated account asset interface', ts: 1698419318540 }
107
- },
108
- },
109
- },
10
+ 'alias': true,
11
+ 'id': 'huobi',
110
12
  });
111
13
  }
112
- requestId() {
113
- const requestId = this.sum(this.safeInteger(this.options, 'requestId', 0), 1);
114
- this.options['requestId'] = requestId;
115
- return requestId.toString();
116
- }
117
- async watchTicker(symbol, params = {}) {
118
- /**
119
- * @method
120
- * @name huobi#watchTicker
121
- * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
122
- * @param {string} symbol unified symbol of the market to fetch the ticker for
123
- * @param {object} [params] extra parameters specific to the huobi api endpoint
124
- * @returns {object} a [ticker structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#ticker-structure}
125
- */
126
- await this.loadMarkets();
127
- const market = this.market(symbol);
128
- symbol = market['symbol'];
129
- const options = this.safeValue(this.options, 'watchTicker', {});
130
- const topic = this.safeString(options, 'name', 'market.{marketId}.detail');
131
- if (topic === 'market.{marketId}.ticker' && market['type'] !== 'spot') {
132
- throw new errors.BadRequest(this.id + ' watchTicker() with name market.{marketId}.ticker is only allowed for spot markets, use market.{marketId}.detail instead');
133
- }
134
- const messageHash = this.implodeParams(topic, { 'marketId': market['id'] });
135
- const url = this.getUrlByMarketType(market['type'], market['linear']);
136
- return await this.subscribePublic(url, symbol, messageHash, undefined, params);
137
- }
138
- handleTicker(client, message) {
139
- //
140
- // "market.btcusdt.detail"
141
- // {
142
- // "ch": "market.btcusdt.detail",
143
- // "ts": 1583494163784,
144
- // "tick": {
145
- // "id": 209988464418,
146
- // "low": 8988,
147
- // "high": 9155.41,
148
- // "open": 9078.91,
149
- // "close": 9136.46,
150
- // "vol": 237813910.5928412,
151
- // "amount": 26184.202558551195,
152
- // "version": 209988464418,
153
- // "count": 265673
154
- // }
155
- // }
156
- // "market.btcusdt.bbo"
157
- // {
158
- // "ch": "market.btcusdt.bbo",
159
- // "ts": 1671941599613,
160
- // "tick": {
161
- // "seqId": 161499562790,
162
- // "ask": 16829.51,
163
- // "askSize": 0.707776,
164
- // "bid": 16829.5,
165
- // "bidSize": 1.685945,
166
- // "quoteTime": 1671941599612,
167
- // "symbol": "btcusdt"
168
- // }
169
- // }
170
- //
171
- const tick = this.safeValue(message, 'tick', {});
172
- const ch = this.safeString(message, 'ch');
173
- const parts = ch.split('.');
174
- const marketId = this.safeString(parts, 1);
175
- const market = this.safeMarket(marketId);
176
- const ticker = this.parseTicker(tick, market);
177
- const timestamp = this.safeValue(message, 'ts');
178
- ticker['timestamp'] = timestamp;
179
- ticker['datetime'] = this.iso8601(timestamp);
180
- const symbol = ticker['symbol'];
181
- this.tickers[symbol] = ticker;
182
- client.resolve(ticker, ch);
183
- return message;
184
- }
185
- async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
186
- /**
187
- * @method
188
- * @name huobi#watchTrades
189
- * @description get the list of most recent trades for a particular symbol
190
- * @param {string} symbol unified symbol of the market to fetch trades for
191
- * @param {int} [since] timestamp in ms of the earliest trade to fetch
192
- * @param {int} [limit] the maximum amount of trades to fetch
193
- * @param {object} [params] extra parameters specific to the huobi api endpoint
194
- * @returns {object[]} a list of [trade structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#public-trades}
195
- */
196
- await this.loadMarkets();
197
- const market = this.market(symbol);
198
- symbol = market['symbol'];
199
- const messageHash = 'market.' + market['id'] + '.trade.detail';
200
- const url = this.getUrlByMarketType(market['type'], market['linear']);
201
- const trades = await this.subscribePublic(url, symbol, messageHash, undefined, params);
202
- if (this.newUpdates) {
203
- limit = trades.getLimit(symbol, limit);
204
- }
205
- return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
206
- }
207
- handleTrades(client, message) {
208
- //
209
- // {
210
- // "ch": "market.btcusdt.trade.detail",
211
- // "ts": 1583495834011,
212
- // "tick": {
213
- // "id": 105004645372,
214
- // "ts": 1583495833751,
215
- // "data": [
216
- // {
217
- // "id": 1.050046453727319e+22,
218
- // "ts": 1583495833751,
219
- // "tradeId": 102090727790,
220
- // "amount": 0.003893,
221
- // "price": 9150.01,
222
- // "direction": "sell"
223
- // }
224
- // ]
225
- // }
226
- // }
227
- //
228
- const tick = this.safeValue(message, 'tick', {});
229
- const data = this.safeValue(tick, 'data', {});
230
- const ch = this.safeString(message, 'ch');
231
- const parts = ch.split('.');
232
- const marketId = this.safeString(parts, 1);
233
- const market = this.safeMarket(marketId);
234
- const symbol = market['symbol'];
235
- let tradesCache = this.safeValue(this.trades, symbol);
236
- if (tradesCache === undefined) {
237
- const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
238
- tradesCache = new Cache.ArrayCache(limit);
239
- this.trades[symbol] = tradesCache;
240
- }
241
- for (let i = 0; i < data.length; i++) {
242
- const trade = this.parseTrade(data[i], market);
243
- tradesCache.append(trade);
244
- }
245
- client.resolve(tradesCache, ch);
246
- return message;
247
- }
248
- async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
249
- /**
250
- * @method
251
- * @name huobi#watchOHLCV
252
- * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
253
- * @param {string} symbol unified symbol of the market to fetch OHLCV data for
254
- * @param {string} timeframe the length of time each candle represents
255
- * @param {int} [since] timestamp in ms of the earliest candle to fetch
256
- * @param {int} [limit] the maximum amount of candles to fetch
257
- * @param {object} [params] extra parameters specific to the huobi api endpoint
258
- * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
259
- */
260
- await this.loadMarkets();
261
- const market = this.market(symbol);
262
- symbol = market['symbol'];
263
- const interval = this.safeString(this.timeframes, timeframe, timeframe);
264
- const messageHash = 'market.' + market['id'] + '.kline.' + interval;
265
- const url = this.getUrlByMarketType(market['type'], market['linear']);
266
- const ohlcv = await this.subscribePublic(url, symbol, messageHash, undefined, params);
267
- if (this.newUpdates) {
268
- limit = ohlcv.getLimit(symbol, limit);
269
- }
270
- return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
271
- }
272
- handleOHLCV(client, message) {
273
- //
274
- // {
275
- // "ch": "market.btcusdt.kline.1min",
276
- // "ts": 1583501786794,
277
- // "tick": {
278
- // "id": 1583501760,
279
- // "open": 9094.5,
280
- // "close": 9094.51,
281
- // "low": 9094.5,
282
- // "high": 9094.51,
283
- // "amount": 0.44639786263800907,
284
- // "vol": 4059.76919054,
285
- // "count": 16
286
- // }
287
- // }
288
- //
289
- const ch = this.safeString(message, 'ch');
290
- const parts = ch.split('.');
291
- const marketId = this.safeString(parts, 1);
292
- const market = this.safeMarket(marketId);
293
- const symbol = market['symbol'];
294
- const interval = this.safeString(parts, 3);
295
- const timeframe = this.findTimeframe(interval);
296
- this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
297
- let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
298
- if (stored === undefined) {
299
- const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
300
- stored = new Cache.ArrayCacheByTimestamp(limit);
301
- this.ohlcvs[symbol][timeframe] = stored;
302
- }
303
- const tick = this.safeValue(message, 'tick');
304
- const parsed = this.parseOHLCV(tick, market);
305
- stored.append(parsed);
306
- client.resolve(stored, ch);
307
- }
308
- async watchOrderBook(symbol, limit = undefined, params = {}) {
309
- /**
310
- * @method
311
- * @name huobi#watchOrderBook
312
- * @see https://huobiapi.github.io/docs/dm/v1/en/#subscribe-market-depth-data
313
- * @see https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#subscribe-incremental-market-depth-data
314
- * @see https://huobiapi.github.io/docs/usdt_swap/v1/en/#general-subscribe-incremental-market-depth-data
315
- * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
316
- * @param {string} symbol unified symbol of the market to fetch the order book for
317
- * @param {int} [limit] the maximum amount of order book entries to return
318
- * @param {object} [params] extra parameters specific to the huobi api endpoint
319
- * @returns {object} A dictionary of [order book structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-book-structure} indexed by market symbols
320
- */
321
- await this.loadMarkets();
322
- const market = this.market(symbol);
323
- symbol = market['symbol'];
324
- const allowedSpotLimits = [150];
325
- const allowedSwapLimits = [20, 150];
326
- limit = (limit === undefined) ? 150 : limit;
327
- if (market['spot'] && !this.inArray(limit, allowedSpotLimits)) {
328
- throw new errors.ExchangeError(this.id + ' watchOrderBook spot market accepts limits of 150 only');
329
- }
330
- if (!market['spot'] && !this.inArray(limit, allowedSwapLimits)) {
331
- throw new errors.ExchangeError(this.id + ' watchOrderBook swap market accepts limits of 20 and 150 only');
332
- }
333
- let messageHash = undefined;
334
- if (market['spot']) {
335
- messageHash = 'market.' + market['id'] + '.mbp.' + limit.toString();
336
- }
337
- else {
338
- messageHash = 'market.' + market['id'] + '.depth.size_' + limit.toString() + '.high_freq';
339
- }
340
- const url = this.getUrlByMarketType(market['type'], market['linear']);
341
- let method = this.handleOrderBookSubscription;
342
- if (!market['spot']) {
343
- params = this.extend(params);
344
- params['data_type'] = 'incremental';
345
- method = undefined;
346
- }
347
- const orderbook = await this.subscribePublic(url, symbol, messageHash, method, params);
348
- return orderbook.limit();
349
- }
350
- handleOrderBookSnapshot(client, message, subscription) {
351
- //
352
- // {
353
- // "id": 1583473663565,
354
- // "rep": "market.btcusdt.mbp.150",
355
- // "status": "ok",
356
- // "ts": 1698359289261,
357
- // "data": {
358
- // "seqNum": 104999417756,
359
- // "bids": [
360
- // [9058.27, 0],
361
- // [9058.43, 0],
362
- // [9058.99, 0],
363
- // ],
364
- // "asks": [
365
- // [9084.27, 0.2],
366
- // [9085.69, 0],
367
- // [9085.81, 0],
368
- // ]
369
- // }
370
- // }
371
- //
372
- const symbol = this.safeString(subscription, 'symbol');
373
- const messageHash = this.safeString(subscription, 'messageHash');
374
- const id = this.safeString(message, 'id');
375
- try {
376
- const orderbook = this.orderbooks[symbol];
377
- const data = this.safeValue(message, 'data');
378
- const messages = orderbook.cache;
379
- const firstMessage = this.safeValue(messages, 0, {});
380
- const snapshot = this.parseOrderBook(data, symbol);
381
- const tick = this.safeValue(firstMessage, 'tick');
382
- const sequence = this.safeInteger(tick, 'seqNum');
383
- const nonce = this.safeInteger(data, 'seqNum');
384
- snapshot['nonce'] = nonce;
385
- const timestamp = this.safeInteger(message, 'ts');
386
- snapshot['timestamp'] = timestamp;
387
- snapshot['datetime'] = this.iso8601(timestamp);
388
- const snapshotLimit = this.safeInteger(subscription, 'limit');
389
- const snapshotOrderBook = this.orderBook(snapshot, snapshotLimit);
390
- client.resolve(snapshotOrderBook, id);
391
- if ((sequence !== undefined) && (nonce < sequence)) {
392
- const maxAttempts = this.handleOption('watchOrderBook', 'maxRetries', 3);
393
- let numAttempts = this.safeInteger(subscription, 'numAttempts', 0);
394
- // retry to synchronize if we have not reached maxAttempts yet
395
- if (numAttempts < maxAttempts) {
396
- // safety guard
397
- if (messageHash in client.subscriptions) {
398
- numAttempts = this.sum(numAttempts, 1);
399
- subscription['numAttempts'] = numAttempts;
400
- client.subscriptions[messageHash] = subscription;
401
- this.spawn(this.watchOrderBookSnapshot, client, message, subscription);
402
- }
403
- }
404
- else {
405
- // throw upon failing to synchronize in maxAttempts
406
- throw new errors.InvalidNonce(this.id + ' failed to synchronize WebSocket feed with the snapshot for symbol ' + symbol + ' in ' + maxAttempts.toString() + ' attempts');
407
- }
408
- }
409
- else {
410
- orderbook.reset(snapshot);
411
- // unroll the accumulated deltas
412
- for (let i = 0; i < messages.length; i++) {
413
- this.handleOrderBookMessage(client, messages[i], orderbook);
414
- }
415
- this.orderbooks[symbol] = orderbook;
416
- client.resolve(orderbook, messageHash);
417
- }
418
- }
419
- catch (e) {
420
- client.reject(e, messageHash);
421
- }
422
- }
423
- async watchOrderBookSnapshot(client, message, subscription) {
424
- const messageHash = this.safeString(subscription, 'messageHash');
425
- try {
426
- const symbol = this.safeString(subscription, 'symbol');
427
- const limit = this.safeInteger(subscription, 'limit');
428
- const params = this.safeValue(subscription, 'params');
429
- const attempts = this.safeInteger(subscription, 'numAttempts', 0);
430
- const market = this.market(symbol);
431
- const url = this.getUrlByMarketType(market['type'], market['linear']);
432
- const requestId = this.requestId();
433
- const request = {
434
- 'req': messageHash,
435
- 'id': requestId,
436
- };
437
- // this is a temporary subscription by a specific requestId
438
- // it has a very short lifetime until the snapshot is received over ws
439
- const snapshotSubscription = {
440
- 'id': requestId,
441
- 'messageHash': messageHash,
442
- 'symbol': symbol,
443
- 'limit': limit,
444
- 'params': params,
445
- 'numAttempts': attempts,
446
- 'method': this.handleOrderBookSnapshot,
447
- };
448
- const orderbook = await this.watch(url, requestId, request, requestId, snapshotSubscription);
449
- return orderbook.limit();
450
- }
451
- catch (e) {
452
- delete client.subscriptions[messageHash];
453
- client.reject(e, messageHash);
454
- }
455
- }
456
- handleDelta(bookside, delta) {
457
- const price = this.safeFloat(delta, 0);
458
- const amount = this.safeFloat(delta, 1);
459
- bookside.store(price, amount);
460
- }
461
- handleDeltas(bookside, deltas) {
462
- for (let i = 0; i < deltas.length; i++) {
463
- this.handleDelta(bookside, deltas[i]);
464
- }
465
- }
466
- handleOrderBookMessage(client, message, orderbook) {
467
- // spot markets
468
- //
469
- // {
470
- // "ch": "market.btcusdt.mbp.150",
471
- // "ts": 1583472025885,
472
- // "tick": {
473
- // "seqNum": 104998984994,
474
- // "prevSeqNum": 104998984977,
475
- // "bids": [
476
- // [9058.27, 0],
477
- // [9058.43, 0],
478
- // [9058.99, 0],
479
- // ],
480
- // "asks": [
481
- // [9084.27, 0.2],
482
- // [9085.69, 0],
483
- // [9085.81, 0],
484
- // ]
485
- // }
486
- // }
487
- //
488
- // non-spot market update
489
- //
490
- // {
491
- // "ch":"market.BTC220218.depth.size_150.high_freq",
492
- // "tick":{
493
- // "asks":[],
494
- // "bids":[
495
- // [43445.74,1],
496
- // [43444.48,0 ],
497
- // [40593.92,9]
498
- // ],
499
- // "ch":"market.BTC220218.depth.size_150.high_freq",
500
- // "event":"update",
501
- // "id":152727500274,
502
- // "mrid":152727500274,
503
- // "ts":1645023376098,
504
- // "version":37536690
505
- // },
506
- // "ts":1645023376098
507
- // }
508
- // non-spot market snapshot
509
- //
510
- // {
511
- // "ch":"market.BTC220218.depth.size_150.high_freq",
512
- // "tick":{
513
- // "asks":[
514
- // [43445.74,1],
515
- // [43444.48,0 ],
516
- // [40593.92,9]
517
- // ],
518
- // "bids":[
519
- // [43445.74,1],
520
- // [43444.48,0 ],
521
- // [40593.92,9]
522
- // ],
523
- // "ch":"market.BTC220218.depth.size_150.high_freq",
524
- // "event":"snapshot",
525
- // "id":152727500274,
526
- // "mrid":152727500274,
527
- // "ts":1645023376098,
528
- // "version":37536690
529
- // },
530
- // "ts":1645023376098
531
- // }
532
- //
533
- const ch = this.safeValue(message, 'ch');
534
- const parts = ch.split('.');
535
- const marketId = this.safeString(parts, 1);
536
- const symbol = this.safeSymbol(marketId);
537
- const tick = this.safeValue(message, 'tick', {});
538
- const seqNum = this.safeInteger2(tick, 'seqNum', 'version');
539
- const prevSeqNum = this.safeInteger(tick, 'prevSeqNum');
540
- const event = this.safeString(tick, 'event');
541
- const timestamp = this.safeInteger(message, 'ts');
542
- if (event === 'snapshot') {
543
- const snapshot = this.parseOrderBook(tick, symbol, timestamp);
544
- orderbook.reset(snapshot);
545
- orderbook['nonce'] = seqNum;
546
- }
547
- if (prevSeqNum !== undefined && prevSeqNum > orderbook['nonce']) {
548
- throw new errors.InvalidNonce(this.id + ' watchOrderBook() received a mesage out of order');
549
- }
550
- if ((prevSeqNum === undefined || prevSeqNum <= orderbook['nonce']) && (seqNum > orderbook['nonce'])) {
551
- const asks = this.safeValue(tick, 'asks', []);
552
- const bids = this.safeValue(tick, 'bids', []);
553
- this.handleDeltas(orderbook['asks'], asks);
554
- this.handleDeltas(orderbook['bids'], bids);
555
- orderbook['nonce'] = seqNum;
556
- orderbook['timestamp'] = timestamp;
557
- orderbook['datetime'] = this.iso8601(timestamp);
558
- }
559
- return orderbook;
560
- }
561
- handleOrderBook(client, message) {
562
- //
563
- // deltas
564
- //
565
- // spot markets
566
- //
567
- // {
568
- // "ch": "market.btcusdt.mbp.150",
569
- // "ts": 1583472025885,
570
- // "tick": {
571
- // "seqNum": 104998984994,
572
- // "prevSeqNum": 104998984977,
573
- // "bids": [
574
- // [9058.27, 0],
575
- // [9058.43, 0],
576
- // [9058.99, 0],
577
- // ],
578
- // "asks": [
579
- // [9084.27, 0.2],
580
- // [9085.69, 0],
581
- // [9085.81, 0],
582
- // ]
583
- // }
584
- // }
585
- //
586
- // non spot markets
587
- //
588
- // {
589
- // "ch":"market.BTC220218.depth.size_150.high_freq",
590
- // "tick":{
591
- // "asks":[],
592
- // "bids":[
593
- // [43445.74,1],
594
- // [43444.48,0 ],
595
- // [40593.92,9]
596
- // ],
597
- // "ch":"market.BTC220218.depth.size_150.high_freq",
598
- // "event":"update",
599
- // "id":152727500274,
600
- // "mrid":152727500274,
601
- // "ts":1645023376098,
602
- // "version":37536690
603
- // },
604
- // "ts":1645023376098
605
- // }
606
- //
607
- const tick = this.safeValue(message, 'tick', {});
608
- const event = this.safeString(tick, 'event');
609
- const messageHash = this.safeString(message, 'ch');
610
- const ch = this.safeValue(message, 'ch');
611
- const parts = ch.split('.');
612
- const marketId = this.safeString(parts, 1);
613
- const symbol = this.safeSymbol(marketId);
614
- let orderbook = this.safeValue(this.orderbooks, symbol);
615
- if (orderbook === undefined) {
616
- const size = this.safeString(parts, 3);
617
- const sizeParts = size.split('_');
618
- const limit = this.safeInteger(sizeParts, 1);
619
- orderbook = this.orderBook({}, limit);
620
- }
621
- if (orderbook['nonce'] === undefined) {
622
- orderbook.cache.push(message);
623
- }
624
- if (event !== undefined || orderbook['nonce'] !== undefined) {
625
- this.orderbooks[symbol] = this.handleOrderBookMessage(client, message, orderbook);
626
- client.resolve(orderbook, messageHash);
627
- }
628
- }
629
- handleOrderBookSubscription(client, message, subscription) {
630
- const symbol = this.safeString(subscription, 'symbol');
631
- const limit = this.safeInteger(subscription, 'limit');
632
- if (symbol in this.orderbooks) {
633
- delete this.orderbooks[symbol];
634
- }
635
- this.orderbooks[symbol] = this.orderBook({}, limit);
636
- if (this.markets[symbol]['spot'] === true) {
637
- this.spawn(this.watchOrderBookSnapshot, client, message, subscription);
638
- }
639
- }
640
- async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
641
- /**
642
- * @method
643
- * @name huobi#watchMyTrades
644
- * @description watches information on multiple trades made by the user
645
- * @param {string} symbol unified market symbol of the market trades were made in
646
- * @param {int} [since] the earliest time in ms to fetch trades for
647
- * @param {int} [limit] the maximum number of trade structures to retrieve
648
- * @param {object} [params] extra parameters specific to the huobi api endpoint
649
- * @returns {object[]} a list of [trade structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#trade-structure
650
- */
651
- this.checkRequiredCredentials();
652
- await this.loadMarkets();
653
- let type = undefined;
654
- let marketId = '*'; // wildcard
655
- let market = undefined;
656
- let messageHash = undefined;
657
- let channel = undefined;
658
- let trades = undefined;
659
- let subType = undefined;
660
- if (symbol !== undefined) {
661
- market = this.market(symbol);
662
- symbol = market['symbol'];
663
- type = market['type'];
664
- subType = market['linear'] ? 'linear' : 'inverse';
665
- marketId = market['lowercaseId'];
666
- }
667
- else {
668
- type = this.safeString(this.options, 'defaultType', 'spot');
669
- type = this.safeString(params, 'type', type);
670
- subType = this.safeString2(this.options, 'subType', 'defaultSubType', 'linear');
671
- subType = this.safeString(params, 'subType', subType);
672
- params = this.omit(params, ['type', 'subType']);
673
- }
674
- if (type === 'spot') {
675
- let mode = undefined;
676
- if (mode === undefined) {
677
- mode = this.safeString2(this.options, 'watchMyTrades', 'mode', '0');
678
- mode = this.safeString(params, 'mode', mode);
679
- params = this.omit(params, 'mode');
680
- }
681
- messageHash = 'trade.clearing' + '#' + marketId + '#' + mode;
682
- channel = messageHash;
683
- }
684
- else {
685
- const channelAndMessageHash = this.getOrderChannelAndMessageHash(type, subType, market, params);
686
- channel = this.safeString(channelAndMessageHash, 0);
687
- const orderMessageHash = this.safeString(channelAndMessageHash, 1);
688
- // we will take advantage of the order messageHash because already handles stuff
689
- // like symbol/margin/subtype/type variations
690
- messageHash = orderMessageHash + ':' + 'trade';
691
- }
692
- trades = await this.subscribePrivate(channel, messageHash, type, subType, params);
693
- if (this.newUpdates) {
694
- limit = trades.getLimit(symbol, limit);
695
- }
696
- return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
697
- }
698
- getOrderChannelAndMessageHash(type, subType, market = undefined, params = {}) {
699
- let messageHash = undefined;
700
- let channel = undefined;
701
- let orderType = this.safeString(this.options, 'orderType', 'orders'); // orders or matchOrders
702
- orderType = this.safeString(params, 'orderType', orderType);
703
- params = this.omit(params, 'orderType');
704
- const marketCode = (market !== undefined) ? market['lowercaseId'] : undefined;
705
- const baseId = (market !== undefined) ? market['lowercaseBaseId'] : undefined;
706
- const prefix = orderType;
707
- messageHash = prefix;
708
- if (subType === 'linear') {
709
- // USDT Margined Contracts Example: LTC/USDT:USDT
710
- const marginMode = this.safeString(params, 'margin', 'cross');
711
- const marginPrefix = (marginMode === 'cross') ? prefix + '_cross' : prefix;
712
- messageHash = marginPrefix;
713
- if (marketCode !== undefined) {
714
- messageHash += '.' + marketCode;
715
- channel = messageHash;
716
- }
717
- else {
718
- channel = marginPrefix + '.' + '*';
719
- }
720
- }
721
- else if (type === 'future') {
722
- // inverse futures Example: BCH/USD:BCH-220408
723
- if (baseId !== undefined) {
724
- channel = prefix + '.' + baseId;
725
- messageHash = channel;
726
- }
727
- else {
728
- channel = prefix + '.' + '*';
729
- }
730
- }
731
- else {
732
- // inverse swaps: Example: BTC/USD:BTC
733
- if (marketCode !== undefined) {
734
- channel = prefix + '.' + marketCode;
735
- messageHash = channel;
736
- }
737
- else {
738
- channel = prefix + '.' + '*';
739
- }
740
- }
741
- return [channel, messageHash];
742
- }
743
- async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
744
- /**
745
- * @method
746
- * @name huobi#watchOrders
747
- * @description watches information on multiple orders made by the user
748
- * @param {string} symbol unified market symbol of the market orders were made in
749
- * @param {int} [since] the earliest time in ms to fetch orders for
750
- * @param {int} [limit] the maximum number of orde structures to retrieve
751
- * @param {object} [params] extra parameters specific to the huobi api endpoint
752
- * @returns {object[]} a list of [order structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-structure}
753
- */
754
- await this.loadMarkets();
755
- let type = undefined;
756
- let subType = undefined;
757
- let market = undefined;
758
- let suffix = '*'; // wildcard
759
- if (symbol !== undefined) {
760
- market = this.market(symbol);
761
- symbol = market['symbol'];
762
- type = market['type'];
763
- suffix = market['lowercaseId'];
764
- subType = market['linear'] ? 'linear' : 'inverse';
765
- }
766
- else {
767
- type = this.safeString(this.options, 'defaultType', 'spot');
768
- type = this.safeString(params, 'type', type);
769
- subType = this.safeString2(this.options, 'subType', 'defaultSubType', 'linear');
770
- subType = this.safeString(params, 'subType', subType);
771
- params = this.omit(params, ['type', 'subType']);
772
- }
773
- let messageHash = undefined;
774
- let channel = undefined;
775
- if (type === 'spot') {
776
- messageHash = 'orders' + '#' + suffix;
777
- channel = messageHash;
778
- }
779
- else {
780
- const channelAndMessageHash = this.getOrderChannelAndMessageHash(type, subType, market, params);
781
- channel = this.safeString(channelAndMessageHash, 0);
782
- messageHash = this.safeString(channelAndMessageHash, 1);
783
- }
784
- const orders = await this.subscribePrivate(channel, messageHash, type, subType, params);
785
- if (this.newUpdates) {
786
- limit = orders.getLimit(symbol, limit);
787
- }
788
- return this.filterBySinceLimit(orders, since, limit, 'timestamp', true);
789
- }
790
- handleOrder(client, message) {
791
- //
792
- // spot
793
- //
794
- // {
795
- // "action":"push",
796
- // "ch":"orders#btcusdt", // or "orders#*" for global subscriptions
797
- // "data": {
798
- // "orderSource": "spot-web",
799
- // "orderCreateTime": 1645116048355,
800
- // "accountId": 44234548,
801
- // "orderPrice": "100",
802
- // "orderSize": "0.05",
803
- // "symbol": "ethusdt",
804
- // "type": "buy-limit",
805
- // "orderId": "478861479986886",
806
- // "eventType": "creation",
807
- // "clientOrderId": '',
808
- // "orderStatus": "submitted"
809
- // }
810
- // }
811
- //
812
- // spot wrapped trade
813
- //
814
- // {
815
- // "action": "push",
816
- // "ch": "orders#ltcusdt",
817
- // "data": {
818
- // "tradePrice": "130.01",
819
- // "tradeVolume": "0.0385",
820
- // "tradeTime": 1648714741525,
821
- // "aggressor": true,
822
- // "execAmt": "0.0385",
823
- // "orderSource": "spot-web",
824
- // "orderSize": "0.0385",
825
- // "remainAmt": "0",
826
- // "tradeId": 101541578884,
827
- // "symbol": "ltcusdt",
828
- // "type": "sell-market",
829
- // "eventType": "trade",
830
- // "clientOrderId": '',
831
- // "orderStatus": "filled",
832
- // "orderId": 509835753860328
833
- // }
834
- // }
835
- //
836
- // non spot order
837
- //
838
- // {
839
- // "contract_type": "swap",
840
- // "pair": "LTC-USDT",
841
- // "business_type": "swap",
842
- // "op": "notify",
843
- // "topic": "orders_cross.ltc-usdt",
844
- // "ts": 1650354508696,
845
- // "symbol": "LTC",
846
- // "contract_code": "LTC-USDT",
847
- // "volume": 1,
848
- // "price": 110.34,
849
- // "order_price_type": "lightning",
850
- // "direction": "sell",
851
- // "offset": "close",
852
- // "status": 6,
853
- // "lever_rate": 1,
854
- // "order_id": "966002354015051776",
855
- // "order_id_str": "966002354015051776",
856
- // "client_order_id": null,
857
- // "order_source": "web",
858
- // "order_type": 1,
859
- // "created_at": 1650354508649,
860
- // "trade_volume": 1,
861
- // "trade_turnover": 11.072,
862
- // "fee": -0.005536,
863
- // "trade_avg_price": 110.72,
864
- // "margin_frozen": 0,
865
- // "profit": -0.045,
866
- // "trade": [
867
- // {
868
- // "trade_fee": -0.005536,
869
- // "fee_asset": "USDT",
870
- // "real_profit": 0.473,
871
- // "profit": -0.045,
872
- // "trade_id": 86678766507,
873
- // "id": "86678766507-966002354015051776-1",
874
- // "trade_volume": 1,
875
- // "trade_price": 110.72,
876
- // "trade_turnover": 11.072,
877
- // "created_at": 1650354508656,
878
- // "role": "taker"
879
- // }
880
- // ],
881
- // "canceled_at": 0,
882
- // "fee_asset": "USDT",
883
- // "margin_asset": "USDT",
884
- // "uid": "359305390",
885
- // "liquidation_type": "0",
886
- // "margin_mode": "cross",
887
- // "margin_account": "USDT",
888
- // "is_tpsl": 0,
889
- // "real_profit": 0.473,
890
- // "trade_partition": "USDT",
891
- // "reduce_only": 1
892
- // }
893
- //
894
- //
895
- const messageHash = this.safeString2(message, 'ch', 'topic');
896
- const data = this.safeValue(message, 'data');
897
- let marketId = this.safeString(message, 'contract_code');
898
- if (marketId === undefined) {
899
- marketId = this.safeString(data, 'symbol');
900
- }
901
- const market = this.safeMarket(marketId);
902
- let parsedOrder = undefined;
903
- if (data !== undefined) {
904
- // spot updates
905
- const eventType = this.safeString(data, 'eventType');
906
- if (eventType === 'trade') {
907
- // when a spot order is filled we get an update message
908
- // with the trade info
909
- const parsedTrade = this.parseOrderTrade(data, market);
910
- // inject trade in existing order by faking an order object
911
- const orderId = this.safeString(parsedTrade, 'order');
912
- const trades = [parsedTrade];
913
- const order = {
914
- 'id': orderId,
915
- 'trades': trades,
916
- 'status': 'closed',
917
- 'symbol': market['symbol'],
918
- };
919
- parsedOrder = order;
920
- }
921
- else {
922
- parsedOrder = this.parseWsOrder(data, market);
923
- }
924
- }
925
- else {
926
- // contract branch
927
- parsedOrder = this.parseWsOrder(message, market);
928
- const rawTrades = this.safeValue(message, 'trade', []);
929
- const tradesLength = rawTrades.length;
930
- if (tradesLength > 0) {
931
- const tradesObject = {
932
- 'trades': rawTrades,
933
- 'ch': messageHash,
934
- 'symbol': marketId,
935
- };
936
- // inject order params in every trade
937
- const extendTradeParams = {
938
- 'order': this.safeString(parsedOrder, 'id'),
939
- 'type': this.safeString(parsedOrder, 'type'),
940
- 'side': this.safeString(parsedOrder, 'side'),
941
- };
942
- // trades arrive inside an order update
943
- // we're forwarding them to handleMyTrade
944
- // so they can be properly resolved
945
- this.handleMyTrade(client, tradesObject, extendTradeParams);
946
- }
947
- }
948
- if (this.orders === undefined) {
949
- const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
950
- this.orders = new Cache.ArrayCacheBySymbolById(limit);
951
- }
952
- const cachedOrders = this.orders;
953
- cachedOrders.append(parsedOrder);
954
- client.resolve(this.orders, messageHash);
955
- // when we make a global subscription (for contracts only) our message hash can't have a symbol/currency attached
956
- // so we're removing it here
957
- let genericMessageHash = messageHash.replace('.' + market['lowercaseId'], '');
958
- genericMessageHash = genericMessageHash.replace('.' + market['lowercaseBaseId'], '');
959
- client.resolve(this.orders, genericMessageHash);
960
- }
961
- parseWsOrder(order, market = undefined) {
962
- //
963
- // spot
964
- //
965
- // {
966
- // "orderSource": "spot-web",
967
- // "orderCreateTime": 1645116048355, // creating only
968
- // "accountId": 44234548,
969
- // "orderPrice": "100",
970
- // "orderSize": "0.05",
971
- // "orderValue": "3.71676361", // market-buy only
972
- // "symbol": "ethusdt",
973
- // "type": "buy-limit",
974
- // "orderId": "478861479986886",
975
- // "eventType": "creation",
976
- // "clientOrderId": '',
977
- // "orderStatus": "submitted"
978
- // "lastActTime":1645118621810 // except creating
979
- // "execAmt":"0"
980
- // }
981
- //
982
- // swap order
983
- //
984
- // {
985
- // "contract_type": "swap",
986
- // "pair": "LTC-USDT",
987
- // "business_type": "swap",
988
- // "op": "notify",
989
- // "topic": "orders_cross.ltc-usdt",
990
- // "ts": 1648717911384,
991
- // "symbol": "LTC",
992
- // "contract_code": "LTC-USDT",
993
- // "volume": 1,
994
- // "price": 129.13,
995
- // "order_price_type": "lightning",
996
- // "direction": "sell",
997
- // "offset": "close",
998
- // "status": 6,
999
- // "lever_rate": 5,
1000
- // "order_id": "959137967397068800",
1001
- // "order_id_str": "959137967397068800",
1002
- // "client_order_id": null,
1003
- // "order_source": "web",
1004
- // "order_type": 1,
1005
- // "created_at": 1648717911344,
1006
- // "trade_volume": 1,
1007
- // "trade_turnover": 12.952,
1008
- // "fee": -0.006476,
1009
- // "trade_avg_price": 129.52,
1010
- // "margin_frozen": 0,
1011
- // "profit": -0.005,
1012
- // "trade": [
1013
- // {
1014
- // "trade_fee": -0.006476,
1015
- // "fee_asset": "USDT",
1016
- // "real_profit": -0.005,
1017
- // "profit": -0.005,
1018
- // "trade_id": 83619995370,
1019
- // "id": "83619995370-959137967397068800-1",
1020
- // "trade_volume": 1,
1021
- // "trade_price": 129.52,
1022
- // "trade_turnover": 12.952,
1023
- // "created_at": 1648717911352,
1024
- // "role": "taker"
1025
- // }
1026
- // ],
1027
- // "canceled_at": 0,
1028
- // "fee_asset": "USDT",
1029
- // "margin_asset": "USDT",
1030
- // "uid": "359305390",
1031
- // "liquidation_type": "0",
1032
- // "margin_mode": "cross",
1033
- // "margin_account": "USDT",
1034
- // "is_tpsl": 0,
1035
- // "real_profit": -0.005,
1036
- // "trade_partition": "USDT",
1037
- // "reduce_only": 1
1038
- // }
1039
- //
1040
- // {
1041
- // "op":"notify",
1042
- // "topic":"orders.ada",
1043
- // "ts":1604388667226,
1044
- // "symbol":"ADA",
1045
- // "contract_type":"quarter",
1046
- // "contract_code":"ADA201225",
1047
- // "volume":1,
1048
- // "price":0.0905,
1049
- // "order_price_type":"post_only",
1050
- // "direction":"sell",
1051
- // "offset":"open",
1052
- // "status":6,
1053
- // "lever_rate":20,
1054
- // "order_id":773207641127878656,
1055
- // "order_id_str":"773207641127878656",
1056
- // "client_order_id":null,
1057
- // "order_source":"web",
1058
- // "order_type":1,
1059
- // "created_at":1604388667146,
1060
- // "trade_volume":1,
1061
- // "trade_turnover":10,
1062
- // "fee":-0.022099447513812154,
1063
- // "trade_avg_price":0.0905,
1064
- // "margin_frozen":0,
1065
- // "profit":0,
1066
- // "trade":[],
1067
- // "canceled_at":0,
1068
- // "fee_asset":"ADA",
1069
- // "uid":"123456789",
1070
- // "liquidation_type":"0",
1071
- // "is_tpsl": 0,
1072
- // "real_profit": 0
1073
- // }
1074
- //
1075
- const lastTradeTimestamp = this.safeInteger2(order, 'lastActTime', 'ts');
1076
- const created = this.safeInteger(order, 'orderCreateTime');
1077
- const marketId = this.safeString2(order, 'contract_code', 'symbol');
1078
- market = this.safeMarket(marketId, market);
1079
- const symbol = this.safeSymbol(marketId, market);
1080
- const amount = this.safeString2(order, 'orderSize', 'volume');
1081
- const status = this.parseOrderStatus(this.safeString2(order, 'orderStatus', 'status'));
1082
- const id = this.safeString2(order, 'orderId', 'order_id');
1083
- const clientOrderId = this.safeString2(order, 'clientOrderId', 'client_order_id');
1084
- const price = this.safeString2(order, 'orderPrice', 'price');
1085
- const filled = this.safeString(order, 'execAmt');
1086
- const typeSide = this.safeString(order, 'type');
1087
- const feeCost = this.safeString(order, 'fee');
1088
- let fee = undefined;
1089
- if (feeCost !== undefined) {
1090
- const feeCurrencyId = this.safeString(order, 'fee_asset');
1091
- fee = {
1092
- 'cost': feeCost,
1093
- 'currency': this.safeCurrencyCode(feeCurrencyId),
1094
- };
1095
- }
1096
- const avgPrice = this.safeString(order, 'trade_avg_price');
1097
- const rawTrades = this.safeValue(order, 'trade');
1098
- let typeSideParts = [];
1099
- if (typeSide !== undefined) {
1100
- typeSideParts = typeSide.split('-');
1101
- }
1102
- let type = this.safeStringLower(typeSideParts, 1);
1103
- if (type === undefined) {
1104
- type = this.safeString(order, 'order_price_type');
1105
- }
1106
- let side = this.safeStringLower(typeSideParts, 0);
1107
- if (side === undefined) {
1108
- side = this.safeString(order, 'direction');
1109
- }
1110
- const cost = this.safeString(order, 'orderValue');
1111
- return this.safeOrder({
1112
- 'info': order,
1113
- 'id': id,
1114
- 'clientOrderId': clientOrderId,
1115
- 'timestamp': created,
1116
- 'datetime': this.iso8601(created),
1117
- 'lastTradeTimestamp': lastTradeTimestamp,
1118
- 'status': status,
1119
- 'symbol': symbol,
1120
- 'type': type,
1121
- 'timeInForce': undefined,
1122
- 'postOnly': undefined,
1123
- 'side': side,
1124
- 'price': price,
1125
- 'amount': amount,
1126
- 'filled': filled,
1127
- 'remaining': undefined,
1128
- 'cost': cost,
1129
- 'fee': fee,
1130
- 'average': avgPrice,
1131
- 'trades': rawTrades,
1132
- }, market);
1133
- }
1134
- parseOrderTrade(trade, market = undefined) {
1135
- // spot private wrapped trade
1136
- //
1137
- // {
1138
- // "tradePrice": "130.01",
1139
- // "tradeVolume": "0.0385",
1140
- // "tradeTime": 1648714741525,
1141
- // "aggressor": true,
1142
- // "execAmt": "0.0385",
1143
- // "orderSource": "spot-web",
1144
- // "orderSize": "0.0385",
1145
- // "remainAmt": "0",
1146
- // "tradeId": 101541578884,
1147
- // "symbol": "ltcusdt",
1148
- // "type": "sell-market",
1149
- // "eventType": "trade",
1150
- // "clientOrderId": '',
1151
- // "orderStatus": "filled",
1152
- // "orderId": 509835753860328
1153
- // }
1154
- //
1155
- market = this.safeMarket(undefined, market);
1156
- const symbol = market['symbol'];
1157
- const tradeId = this.safeString(trade, 'tradeId');
1158
- const price = this.safeString(trade, 'tradePrice');
1159
- const amount = this.safeString(trade, 'tradeVolume');
1160
- const order = this.safeString(trade, 'orderId');
1161
- const timestamp = this.safeInteger(trade, 'tradeTime');
1162
- let type = this.safeString(trade, 'type');
1163
- let side = undefined;
1164
- if (type !== undefined) {
1165
- const typeParts = type.split('-');
1166
- side = typeParts[0];
1167
- type = typeParts[1];
1168
- }
1169
- const aggressor = this.safeValue(trade, 'aggressor');
1170
- let takerOrMaker = undefined;
1171
- if (aggressor !== undefined) {
1172
- takerOrMaker = aggressor ? 'taker' : 'maker';
1173
- }
1174
- return this.safeTrade({
1175
- 'info': trade,
1176
- 'timestamp': timestamp,
1177
- 'datetime': this.iso8601(timestamp),
1178
- 'symbol': symbol,
1179
- 'id': tradeId,
1180
- 'order': order,
1181
- 'type': type,
1182
- 'takerOrMaker': takerOrMaker,
1183
- 'side': side,
1184
- 'price': price,
1185
- 'amount': amount,
1186
- 'cost': undefined,
1187
- 'fee': undefined,
1188
- }, market);
1189
- }
1190
- async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
1191
- /**
1192
- * @method
1193
- * @name huobi#watchPositions
1194
- * @see https://www.huobi.com/en-in/opend/newApiPages/?id=8cb7de1c-77b5-11ed-9966-0242ac110003
1195
- * @see https://www.huobi.com/en-in/opend/newApiPages/?id=8cb7df0f-77b5-11ed-9966-0242ac110003
1196
- * @see https://www.huobi.com/en-in/opend/newApiPages/?id=28c34a7d-77ae-11ed-9966-0242ac110003
1197
- * @see https://www.huobi.com/en-in/opend/newApiPages/?id=5d5156b5-77b6-11ed-9966-0242ac110003
1198
- * @description watch all open positions. Note: huobi has one channel for each marginMode and type
1199
- * @param {string[]|undefined} symbols list of unified market symbols
1200
- * @param {object} params extra parameters specific to the huobi api endpoint
1201
- * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
1202
- */
1203
- await this.loadMarkets();
1204
- let market = undefined;
1205
- let messageHash = '';
1206
- if (!this.isEmpty(symbols)) {
1207
- market = this.getMarketFromSymbols(symbols);
1208
- messageHash = '::' + symbols.join(',');
1209
- }
1210
- let type = undefined;
1211
- let subType = undefined;
1212
- if (market !== undefined) {
1213
- type = market['type'];
1214
- subType = market['linear'] ? 'linear' : 'inverse';
1215
- }
1216
- else {
1217
- [type, params] = this.handleMarketTypeAndParams('watchPositions', market, params);
1218
- if (type === 'spot') {
1219
- type = 'future';
1220
- }
1221
- [subType, params] = this.handleOptionAndParams(params, 'watchPositions', 'subType', subType);
1222
- }
1223
- symbols = this.marketSymbols(symbols);
1224
- let marginMode = undefined;
1225
- [marginMode, params] = this.handleMarginModeAndParams('watchPositions', params, 'cross');
1226
- const isLinear = (subType === 'linear');
1227
- const url = this.getUrlByMarketType(type, isLinear, true);
1228
- messageHash = marginMode + ':positions' + messageHash;
1229
- const channel = (marginMode === 'cross') ? 'positions_cross.*' : 'positions.*';
1230
- const newPositions = await this.subscribePrivate(channel, messageHash, type, subType, params);
1231
- if (this.newUpdates) {
1232
- return newPositions;
1233
- }
1234
- return this.filterBySymbolsSinceLimit(this.positions[url][marginMode], symbols, since, limit, false);
1235
- }
1236
- handlePositions(client, message) {
1237
- //
1238
- // {
1239
- // op: 'notify',
1240
- // topic: 'positions_cross',
1241
- // ts: 1696767149650,
1242
- // event: 'snapshot',
1243
- // data: [
1244
- // {
1245
- // contract_type: 'swap',
1246
- // pair: 'BTC-USDT',
1247
- // business_type: 'swap',
1248
- // liquidation_price: null,
1249
- // symbol: 'BTC',
1250
- // contract_code: 'BTC-USDT',
1251
- // volume: 1,
1252
- // available: 1,
1253
- // frozen: 0,
1254
- // cost_open: 27802.2,
1255
- // cost_hold: 27802.2,
1256
- // profit_unreal: 0.0175,
1257
- // profit_rate: 0.000629446590557581,
1258
- // profit: 0.0175,
1259
- // margin_asset: 'USDT',
1260
- // position_margin: 27.8197,
1261
- // lever_rate: 1,
1262
- // direction: 'buy',
1263
- // last_price: 27819.7,
1264
- // margin_mode: 'cross',
1265
- // margin_account: 'USDT',
1266
- // trade_partition: 'USDT',
1267
- // position_mode: 'dual_side'
1268
- // },
1269
- // ]
1270
- // }
1271
- //
1272
- const url = client.url;
1273
- const topic = this.safeString(message, 'topic', '');
1274
- const marginMode = (topic === 'positions_cross') ? 'cross' : 'isolated';
1275
- if (this.positions === undefined) {
1276
- this.positions = {};
1277
- }
1278
- const clientPositions = this.safeValue(this.positions, url);
1279
- if (clientPositions === undefined) {
1280
- this.positions[url] = {};
1281
- }
1282
- const clientMarginModePositions = this.safeValue(clientPositions, marginMode);
1283
- if (clientMarginModePositions === undefined) {
1284
- this.positions[url][marginMode] = new Cache.ArrayCacheBySymbolBySide();
1285
- }
1286
- const cache = this.positions[url][marginMode];
1287
- const rawPositions = this.safeValue(message, 'data', []);
1288
- const newPositions = [];
1289
- const timestamp = this.safeInteger(message, 'ts');
1290
- for (let i = 0; i < rawPositions.length; i++) {
1291
- const rawPosition = rawPositions[i];
1292
- const position = this.parsePosition(rawPosition);
1293
- position['timestamp'] = timestamp;
1294
- position['datetime'] = this.iso8601(timestamp);
1295
- newPositions.push(position);
1296
- cache.append(position);
1297
- }
1298
- const messageHashes = this.findMessageHashes(client, marginMode + ':positions::');
1299
- for (let i = 0; i < messageHashes.length; i++) {
1300
- const messageHash = messageHashes[i];
1301
- const parts = messageHash.split('::');
1302
- const symbolsString = parts[1];
1303
- const symbols = symbolsString.split(',');
1304
- const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
1305
- if (!this.isEmpty(positions)) {
1306
- client.resolve(positions, messageHash);
1307
- }
1308
- }
1309
- client.resolve(newPositions, marginMode + ':positions');
1310
- }
1311
- async watchBalance(params = {}) {
1312
- /**
1313
- * @method
1314
- * @name huobi#watchBalance
1315
- * @description watch balance and get the amount of funds available for trading or funds locked in orders
1316
- * @param {object} [params] extra parameters specific to the huobi api endpoint
1317
- * @returns {object} a [balance structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#balance-structure}
1318
- */
1319
- let type = undefined;
1320
- [type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
1321
- let subType = undefined;
1322
- [subType, params] = this.handleSubTypeAndParams('watchBalance', undefined, params, 'linear');
1323
- const isUnifiedAccount = this.safeValue2(params, 'isUnifiedAccount', 'unified', false);
1324
- params = this.omit(params, ['isUnifiedAccount', 'unified']);
1325
- await this.loadMarkets();
1326
- let messageHash = undefined;
1327
- let channel = undefined;
1328
- let marginMode = undefined;
1329
- if (type === 'spot') {
1330
- let mode = this.safeString2(this.options, 'watchBalance', 'mode', '2');
1331
- mode = this.safeString(params, 'mode', mode);
1332
- messageHash = 'accounts.update' + '#' + mode;
1333
- channel = messageHash;
1334
- }
1335
- else {
1336
- const symbol = this.safeString(params, 'symbol');
1337
- const currency = this.safeString(params, 'currency');
1338
- const market = (symbol !== undefined) ? this.market(symbol) : undefined;
1339
- const currencyCode = (currency !== undefined) ? this.currency(currency) : undefined;
1340
- marginMode = this.safeString(params, 'margin', 'cross');
1341
- params = this.omit(params, ['currency', 'symbol', 'margin']);
1342
- let prefix = 'accounts';
1343
- messageHash = prefix;
1344
- if (subType === 'linear') {
1345
- if (isUnifiedAccount) {
1346
- // usdt contracts account
1347
- prefix = 'accounts_unify';
1348
- messageHash = prefix;
1349
- channel = prefix + '.' + 'usdt';
1350
- }
1351
- else {
1352
- // usdt contracts account
1353
- prefix = (marginMode === 'cross') ? prefix + '_cross' : prefix;
1354
- messageHash = prefix;
1355
- if (marginMode === 'isolated') {
1356
- // isolated margin only allows filtering by symbol3
1357
- if (symbol !== undefined) {
1358
- messageHash += '.' + market['id'];
1359
- channel = messageHash;
1360
- }
1361
- else {
1362
- // subscribe to all
1363
- channel = prefix + '.' + '*';
1364
- }
1365
- }
1366
- else {
1367
- // cross margin
1368
- if (currencyCode !== undefined) {
1369
- channel = prefix + '.' + currencyCode['id'];
1370
- messageHash = channel;
1371
- }
1372
- else {
1373
- // subscribe to all
1374
- channel = prefix + '.' + '*';
1375
- }
1376
- }
1377
- }
1378
- }
1379
- else if (type === 'future') {
1380
- // inverse futures account
1381
- if (currencyCode !== undefined) {
1382
- messageHash += '.' + currencyCode['id'];
1383
- channel = messageHash;
1384
- }
1385
- else {
1386
- // subscribe to all
1387
- channel = prefix + '.' + '*';
1388
- }
1389
- }
1390
- else {
1391
- // inverse swaps account
1392
- if (market !== undefined) {
1393
- messageHash += '.' + market['id'];
1394
- channel = messageHash;
1395
- }
1396
- else {
1397
- // subscribe to all
1398
- channel = prefix + '.' + '*';
1399
- }
1400
- }
1401
- }
1402
- const subscriptionParams = {
1403
- 'type': type,
1404
- 'subType': subType,
1405
- 'margin': marginMode,
1406
- };
1407
- // we are differentiating the channel from the messageHash for global subscriptions (*)
1408
- // because huobi returns a different topic than the topic sent. Example: we send
1409
- // "accounts.*" and "accounts" is returned so we're setting channel = "accounts.*" and
1410
- // messageHash = "accounts" allowing handleBalance to freely resolve the topic in the message
1411
- return await this.subscribePrivate(channel, messageHash, type, subType, params, subscriptionParams);
1412
- }
1413
- handleBalance(client, message) {
1414
- // spot
1415
- //
1416
- // {
1417
- // "action": "push",
1418
- // "ch": "accounts.update#0",
1419
- // "data": {
1420
- // "currency": "btc",
1421
- // "accountId": 123456,
1422
- // "balance": "23.111",
1423
- // "available": "2028.699426619837209087",
1424
- // "changeType": "transfer",
1425
- // "accountType":"trade",
1426
- // "seqNum": "86872993928",
1427
- // "changeTime": 1568601800000
1428
- // }
1429
- // }
1430
- //
1431
- // inverse future
1432
- //
1433
- // {
1434
- // "op":"notify",
1435
- // "topic":"accounts.ada",
1436
- // "ts":1604388667226,
1437
- // "event":"order.match",
1438
- // "data":[
1439
- // {
1440
- // "symbol":"ADA",
1441
- // "margin_balance":446.417641681222726716,
1442
- // "margin_static":445.554085945257745136,
1443
- // "margin_position":11.049723756906077348,
1444
- // "margin_frozen":0,
1445
- // "margin_available":435.367917924316649368,
1446
- // "profit_real":21.627049781983019459,
1447
- // "profit_unreal":0.86355573596498158,
1448
- // "risk_rate":40.000796572150656768,
1449
- // "liquidation_price":0.018674308027108984,
1450
- // "withdraw_available":423.927036163274725677,
1451
- // "lever_rate":20,
1452
- // "adjust_factor":0.4
1453
- // }
1454
- // ],
1455
- // "uid":"123456789"
1456
- // }
1457
- //
1458
- // usdt / linear future, swap
1459
- //
1460
- // {
1461
- // "op":"notify",
1462
- // "topic":"accounts.btc-usdt", // or "accounts" for global subscriptions
1463
- // "ts":1603711370689,
1464
- // "event":"order.open",
1465
- // "data":[
1466
- // {
1467
- // "margin_mode":"cross",
1468
- // "margin_account":"USDT",
1469
- // "margin_asset":"USDT",
1470
- // "margin_balance":30.959342395,
1471
- // "margin_static":30.959342395,
1472
- // "margin_position":0,
1473
- // "margin_frozen":10,
1474
- // "profit_real":0,
1475
- // "profit_unreal":0,
1476
- // "withdraw_available":20.959342395,
1477
- // "risk_rate":153.796711975,
1478
- // "position_mode":"dual_side",
1479
- // "contract_detail":[
1480
- // {
1481
- // "symbol":"LTC",
1482
- // "contract_code":"LTC-USDT",
1483
- // "margin_position":0,
1484
- // "margin_frozen":0,
1485
- // "margin_available":20.959342395,
1486
- // "profit_unreal":0,
1487
- // "liquidation_price":null,
1488
- // "lever_rate":1,
1489
- // "adjust_factor":0.01,
1490
- // "contract_type":"swap",
1491
- // "pair":"LTC-USDT",
1492
- // "business_type":"swap",
1493
- // "trade_partition":"USDT"
1494
- // },
1495
- // ],
1496
- // "futures_contract_detail":[],
1497
- // }
1498
- // ]
1499
- // }
1500
- //
1501
- // inverse future
1502
- //
1503
- // {
1504
- // "op":"notify",
1505
- // "topic":"accounts.ada",
1506
- // "ts":1604388667226,
1507
- // "event":"order.match",
1508
- // "data":[
1509
- // {
1510
- // "symbol":"ADA",
1511
- // "margin_balance":446.417641681222726716,
1512
- // "margin_static":445.554085945257745136,
1513
- // "margin_position":11.049723756906077348,
1514
- // "margin_frozen":0,
1515
- // "margin_available":435.367917924316649368,
1516
- // "profit_real":21.627049781983019459,
1517
- // "profit_unreal":0.86355573596498158,
1518
- // "risk_rate":40.000796572150656768,
1519
- // "liquidation_price":0.018674308027108984,
1520
- // "withdraw_available":423.927036163274725677,
1521
- // "lever_rate":20,
1522
- // "adjust_factor":0.4
1523
- // }
1524
- // ],
1525
- // "uid":"123456789"
1526
- // }
1527
- //
1528
- const channel = this.safeString(message, 'ch');
1529
- const data = this.safeValue(message, 'data', []);
1530
- const timestamp = this.safeInteger(data, 'changeTime', this.safeInteger(message, 'ts'));
1531
- this.balance['timestamp'] = timestamp;
1532
- this.balance['datetime'] = this.iso8601(timestamp);
1533
- this.balance['info'] = data;
1534
- if (channel !== undefined) {
1535
- // spot balance
1536
- const currencyId = this.safeString(data, 'currency');
1537
- const code = this.safeCurrencyCode(currencyId);
1538
- const account = this.account();
1539
- account['free'] = this.safeString(data, 'available');
1540
- account['total'] = this.safeString(data, 'balance');
1541
- this.balance[code] = account;
1542
- this.balance = this.safeBalance(this.balance);
1543
- client.resolve(this.balance, channel);
1544
- }
1545
- else {
1546
- // contract balance
1547
- const dataLength = data.length;
1548
- if (dataLength === 0) {
1549
- return;
1550
- }
1551
- const first = this.safeValue(data, 0, {});
1552
- const topic = this.safeString(message, 'topic');
1553
- const splitTopic = topic.split('.');
1554
- let messageHash = this.safeString(splitTopic, 0);
1555
- let subscription = this.safeValue2(client.subscriptions, messageHash, messageHash + '.*');
1556
- if (subscription === undefined) {
1557
- // if subscription not found means that we subscribed to a specific currency/symbol
1558
- // and we use the first data entry to find it
1559
- // Example: topic = 'accounts'
1560
- // client.subscription hash = 'accounts.usdt'
1561
- // we do 'accounts' + '.' + data[0]]['margin_asset'] to get it
1562
- const currencyId = this.safeString2(first, 'margin_asset', 'symbol');
1563
- messageHash += '.' + currencyId.toLowerCase();
1564
- subscription = this.safeValue(client.subscriptions, messageHash);
1565
- }
1566
- const type = this.safeString(subscription, 'type');
1567
- const subType = this.safeString(subscription, 'subType');
1568
- if (topic === 'accounts_unify') {
1569
- // {
1570
- // "margin_asset": "USDT",
1571
- // "margin_static": 10,
1572
- // "cross_margin_static": 10,
1573
- // "margin_balance": 10,
1574
- // "cross_profit_unreal": 0,
1575
- // "margin_frozen": 0,
1576
- // "withdraw_available": 10,
1577
- // "cross_risk_rate": null,
1578
- // "cross_swap": [],
1579
- // "cross_future": [],
1580
- // "isolated_swap": []
1581
- // }
1582
- const marginAsset = this.safeString(first, 'margin_asset');
1583
- const code = this.safeCurrencyCode(marginAsset);
1584
- const marginFrozen = this.safeString(first, 'margin_frozen');
1585
- const unifiedAccount = this.account();
1586
- unifiedAccount['free'] = this.safeString(first, 'withdraw_available');
1587
- unifiedAccount['used'] = marginFrozen;
1588
- this.balance[code] = unifiedAccount;
1589
- this.balance = this.safeBalance(this.balance);
1590
- client.resolve(this.balance, 'accounts_unify');
1591
- }
1592
- else if (subType === 'linear') {
1593
- const margin = this.safeString(subscription, 'margin');
1594
- if (margin === 'cross') {
1595
- const fieldName = (type === 'future') ? 'futures_contract_detail' : 'contract_detail';
1596
- const balances = this.safeValue(first, fieldName, []);
1597
- const balancesLength = balances.length;
1598
- if (balancesLength > 0) {
1599
- for (let i = 0; i < balances.length; i++) {
1600
- const balance = balances[i];
1601
- const marketId = this.safeString2(balance, 'contract_code', 'margin_account');
1602
- const market = this.safeMarket(marketId);
1603
- const currencyId = this.safeString(balance, 'margin_asset');
1604
- const currency = this.safeCurrency(currencyId);
1605
- const code = this.safeString(market, 'settle', currency['code']);
1606
- // the exchange outputs positions for delisted markets
1607
- // https://www.huobi.com/support/en-us/detail/74882968522337
1608
- // we skip it if the market was delisted
1609
- if (code !== undefined) {
1610
- const account = this.account();
1611
- account['free'] = this.safeString2(balance, 'margin_balance', 'margin_available');
1612
- account['used'] = this.safeString(balance, 'margin_frozen');
1613
- const accountsByCode = {};
1614
- accountsByCode[code] = account;
1615
- const symbol = market['symbol'];
1616
- this.balance[symbol] = this.safeBalance(accountsByCode);
1617
- }
1618
- }
1619
- }
1620
- }
1621
- else {
1622
- // isolated margin
1623
- for (let i = 0; i < data.length; i++) {
1624
- const isolatedBalance = data[i];
1625
- const account = this.account();
1626
- account['free'] = this.safeString(isolatedBalance, 'margin_balance', 'margin_available');
1627
- account['used'] = this.safeString(isolatedBalance, 'margin_frozen');
1628
- const currencyId = this.safeString2(isolatedBalance, 'margin_asset', 'symbol');
1629
- const code = this.safeCurrencyCode(currencyId);
1630
- this.balance[code] = account;
1631
- this.balance = this.safeBalance(this.balance);
1632
- }
1633
- }
1634
- }
1635
- else {
1636
- // inverse branch
1637
- for (let i = 0; i < data.length; i++) {
1638
- const balance = data[i];
1639
- const currencyId = this.safeString(balance, 'symbol');
1640
- const code = this.safeCurrencyCode(currencyId);
1641
- const account = this.account();
1642
- account['free'] = this.safeString(balance, 'margin_available');
1643
- account['used'] = this.safeString(balance, 'margin_frozen');
1644
- this.balance[code] = account;
1645
- this.balance = this.safeBalance(this.balance);
1646
- }
1647
- }
1648
- client.resolve(this.balance, messageHash);
1649
- }
1650
- }
1651
- handleSubscriptionStatus(client, message) {
1652
- //
1653
- // {
1654
- // "id": 1583414227,
1655
- // "status": "ok",
1656
- // "subbed": "market.btcusdt.mbp.150",
1657
- // "ts": 1583414229143
1658
- // }
1659
- //
1660
- const id = this.safeString(message, 'id');
1661
- const subscriptionsById = this.indexBy(client.subscriptions, 'id');
1662
- const subscription = this.safeValue(subscriptionsById, id);
1663
- if (subscription !== undefined) {
1664
- const method = this.safeValue(subscription, 'method');
1665
- if (method !== undefined) {
1666
- return method.call(this, client, message, subscription);
1667
- }
1668
- // clean up
1669
- if (id in client.subscriptions) {
1670
- delete client.subscriptions[id];
1671
- }
1672
- }
1673
- return message;
1674
- }
1675
- handleSystemStatus(client, message) {
1676
- //
1677
- // todo: answer the question whether handleSystemStatus should be renamed
1678
- // and unified as handleStatus for any usage pattern that
1679
- // involves system status and maintenance updates
1680
- //
1681
- // {
1682
- // "id": "1578090234088", // connectId
1683
- // "type": "welcome",
1684
- // }
1685
- //
1686
- return message;
1687
- }
1688
- handleSubject(client, message) {
1689
- // spot
1690
- // {
1691
- // "ch": "market.btcusdt.mbp.150",
1692
- // "ts": 1583472025885,
1693
- // "tick": {
1694
- // "seqNum": 104998984994,
1695
- // "prevSeqNum": 104998984977,
1696
- // "bids": [
1697
- // [9058.27, 0],
1698
- // [9058.43, 0],
1699
- // [9058.99, 0],
1700
- // ],
1701
- // "asks": [
1702
- // [9084.27, 0.2],
1703
- // [9085.69, 0],
1704
- // [9085.81, 0],
1705
- // ]
1706
- // }
1707
- // }
1708
- // non spot
1709
- //
1710
- // {
1711
- // "ch":"market.BTC220218.depth.size_150.high_freq",
1712
- // "tick":{
1713
- // "asks":[],
1714
- // "bids":[
1715
- // [43445.74,1],
1716
- // [43444.48,0 ],
1717
- // [40593.92,9]
1718
- // ],
1719
- // "ch":"market.BTC220218.depth.size_150.high_freq",
1720
- // "event":"update",
1721
- // "id":152727500274,
1722
- // "mrid":152727500274,
1723
- // "ts":1645023376098,
1724
- // "version":37536690
1725
- // },
1726
- // "ts":1645023376098
1727
- // }
1728
- //
1729
- // spot private trade
1730
- //
1731
- // {
1732
- // "action":"push",
1733
- // "ch":"trade.clearing#ltcusdt#1",
1734
- // "data":{
1735
- // "eventType":"trade",
1736
- // "symbol":"ltcusdt",
1737
- // // ...
1738
- // },
1739
- // }
1740
- //
1741
- // spot order
1742
- //
1743
- // {
1744
- // "action":"push",
1745
- // "ch":"orders#btcusdt",
1746
- // "data": {
1747
- // "orderSide":"buy",
1748
- // "lastActTime":1583853365586,
1749
- // "clientOrderId":"abc123",
1750
- // "orderStatus":"rejected",
1751
- // "symbol":"btcusdt",
1752
- // "eventType":"trigger",
1753
- // "errCode": 2002,
1754
- // "errMessage":"invalid.client.order.id (NT)"
1755
- // }
1756
- // }
1757
- //
1758
- // contract order
1759
- //
1760
- // {
1761
- // "op":"notify",
1762
- // "topic":"orders.ada",
1763
- // "ts":1604388667226,
1764
- // // ?
1765
- // }
1766
- //
1767
- const ch = this.safeValue(message, 'ch', '');
1768
- const parts = ch.split('.');
1769
- const type = this.safeString(parts, 0);
1770
- if (type === 'market') {
1771
- const methodName = this.safeString(parts, 2);
1772
- const methods = {
1773
- 'depth': this.handleOrderBook,
1774
- 'mbp': this.handleOrderBook,
1775
- 'detail': this.handleTicker,
1776
- 'bbo': this.handleTicker,
1777
- 'ticker': this.handleTicker,
1778
- 'trade': this.handleTrades,
1779
- 'kline': this.handleOHLCV,
1780
- };
1781
- const method = this.safeValue(methods, methodName);
1782
- if (method === undefined) {
1783
- return message;
1784
- }
1785
- else {
1786
- return method.call(this, client, message);
1787
- }
1788
- }
1789
- // private spot subjects
1790
- const privateParts = ch.split('#');
1791
- const privateType = this.safeString(privateParts, 0, '');
1792
- if (privateType === 'trade.clearing') {
1793
- this.handleMyTrade(client, message);
1794
- return;
1795
- }
1796
- if (privateType.indexOf('accounts.update') >= 0) {
1797
- this.handleBalance(client, message);
1798
- return;
1799
- }
1800
- if (privateType === 'orders') {
1801
- this.handleOrder(client, message);
1802
- return;
1803
- }
1804
- // private contract subjects
1805
- const op = this.safeString(message, 'op');
1806
- if (op === 'notify') {
1807
- const topic = this.safeString(message, 'topic', '');
1808
- if (topic.indexOf('orders') >= 0) {
1809
- this.handleOrder(client, message);
1810
- }
1811
- if (topic.indexOf('account') >= 0) {
1812
- this.handleBalance(client, message);
1813
- }
1814
- if (topic.indexOf('positions') >= 0) {
1815
- this.handlePositions(client, message);
1816
- }
1817
- }
1818
- }
1819
- async pong(client, message) {
1820
- //
1821
- // { ping: 1583491673714 }
1822
- // { action: "ping", data: { ts: 1645108204665 } }
1823
- // { op: "ping", ts: "1645202800015" }
1824
- //
1825
- try {
1826
- const ping = this.safeInteger(message, 'ping');
1827
- if (ping !== undefined) {
1828
- await client.send({ 'pong': ping });
1829
- return;
1830
- }
1831
- const action = this.safeString(message, 'action');
1832
- if (action === 'ping') {
1833
- const data = this.safeValue(message, 'data');
1834
- const pingTs = this.safeInteger(data, 'ts');
1835
- await client.send({ 'action': 'pong', 'data': { 'ts': pingTs } });
1836
- return;
1837
- }
1838
- const op = this.safeString(message, 'op');
1839
- if (op === 'ping') {
1840
- const pingTs = this.safeInteger(message, 'ts');
1841
- await client.send({ 'op': 'pong', 'ts': pingTs });
1842
- }
1843
- }
1844
- catch (e) {
1845
- const error = new errors.NetworkError(this.id + ' pong failed ' + this.json(e));
1846
- client.reset(error);
1847
- }
1848
- }
1849
- handlePing(client, message) {
1850
- this.spawn(this.pong, client, message);
1851
- }
1852
- handleAuthenticate(client, message) {
1853
- //
1854
- // spot
1855
- //
1856
- // {
1857
- // "action": "req",
1858
- // "code": 200,
1859
- // "ch": "auth",
1860
- // "data": {}
1861
- // }
1862
- //
1863
- // non spot
1864
- //
1865
- // {
1866
- // "op": "auth",
1867
- // "type": "api",
1868
- // "err-code": 0,
1869
- // "ts": 1645200307319,
1870
- // "data": { "user-id": "35930539" }
1871
- // }
1872
- //
1873
- const promise = client.futures['authenticated'];
1874
- promise.resolve(message);
1875
- }
1876
- handleErrorMessage(client, message) {
1877
- //
1878
- // {
1879
- // "action": "sub",
1880
- // "code": 2002,
1881
- // "ch": "accounts.update#2",
1882
- // "message": "invalid.auth.state"
1883
- // }
1884
- //
1885
- // {
1886
- // "ts": 1586323747018,
1887
- // "status": "error",
1888
- // 'err-code': "bad-request",
1889
- // 'err-msg': "invalid mbp.150.symbol linkusdt",
1890
- // "id": "2"
1891
- // }
1892
- //
1893
- // {
1894
- // "op": "sub",
1895
- // "cid": "1",
1896
- // "topic": "accounts_unify.USDT",
1897
- // "err-code": 4007,
1898
- // 'err-msg': "Non - single account user is not available, please check through the cross and isolated account asset interface",
1899
- // "ts": 1698419490189
1900
- // }
1901
- //
1902
- const status = this.safeString(message, 'status');
1903
- if (status === 'error') {
1904
- const id = this.safeString(message, 'id');
1905
- const subscriptionsById = this.indexBy(client.subscriptions, 'id');
1906
- const subscription = this.safeValue(subscriptionsById, id);
1907
- if (subscription !== undefined) {
1908
- const errorCode = this.safeString(message, 'err-code');
1909
- try {
1910
- this.throwExactlyMatchedException(this.exceptions['ws']['exact'], errorCode, this.json(message));
1911
- }
1912
- catch (e) {
1913
- const messageHash = this.safeString(subscription, 'messageHash');
1914
- client.reject(e, messageHash);
1915
- client.reject(e, id);
1916
- if (id in client.subscriptions) {
1917
- delete client.subscriptions[id];
1918
- }
1919
- }
1920
- }
1921
- return false;
1922
- }
1923
- const code = this.safeInteger2(message, 'code', 'err-code');
1924
- if (code !== undefined && ((code !== 200) && (code !== 0))) {
1925
- const feedback = this.id + ' ' + this.json(message);
1926
- try {
1927
- this.throwExactlyMatchedException(this.exceptions['ws']['exact'], code, feedback);
1928
- }
1929
- catch (e) {
1930
- if (e instanceof errors.AuthenticationError) {
1931
- client.reject(e, 'auth');
1932
- const method = 'auth';
1933
- if (method in client.subscriptions) {
1934
- delete client.subscriptions[method];
1935
- }
1936
- return false;
1937
- }
1938
- else {
1939
- client.reject(e);
1940
- }
1941
- }
1942
- }
1943
- return message;
1944
- }
1945
- handleMessage(client, message) {
1946
- if (this.handleErrorMessage(client, message)) {
1947
- //
1948
- // {"id":1583414227,"status":"ok","subbed":"market.btcusdt.mbp.150","ts":1583414229143}
1949
- //
1950
- // first ping format
1951
- //
1952
- // {"ping": 1645106821667 }
1953
- //
1954
- // second ping format
1955
- //
1956
- // {"action":"ping","data":{"ts":1645106821667}}
1957
- //
1958
- // third pong format
1959
- //
1960
- //
1961
- // auth spot
1962
- //
1963
- // {
1964
- // "action": "req",
1965
- // "code": 200,
1966
- // "ch": "auth",
1967
- // "data": {}
1968
- // }
1969
- //
1970
- // auth non spot
1971
- //
1972
- // {
1973
- // "op": "auth",
1974
- // "type": "api",
1975
- // "err-code": 0,
1976
- // "ts": 1645200307319,
1977
- // "data": { "user-id": "35930539" }
1978
- // }
1979
- //
1980
- // trade
1981
- //
1982
- // {
1983
- // "action":"push",
1984
- // "ch":"trade.clearing#ltcusdt#1",
1985
- // "data":{
1986
- // "eventType":"trade",
1987
- // // ?
1988
- // }
1989
- // }
1990
- //
1991
- if ('id' in message) {
1992
- this.handleSubscriptionStatus(client, message);
1993
- return;
1994
- }
1995
- if ('action' in message) {
1996
- const action = this.safeString(message, 'action');
1997
- if (action === 'ping') {
1998
- this.handlePing(client, message);
1999
- return;
2000
- }
2001
- if (action === 'sub') {
2002
- this.handleSubscriptionStatus(client, message);
2003
- return;
2004
- }
2005
- }
2006
- if ('ch' in message) {
2007
- if (message['ch'] === 'auth') {
2008
- this.handleAuthenticate(client, message);
2009
- return;
2010
- }
2011
- else {
2012
- // route by channel aka topic aka subject
2013
- this.handleSubject(client, message);
2014
- return;
2015
- }
2016
- }
2017
- if ('op' in message) {
2018
- const op = this.safeString(message, 'op');
2019
- if (op === 'ping') {
2020
- this.handlePing(client, message);
2021
- return;
2022
- }
2023
- if (op === 'auth') {
2024
- this.handleAuthenticate(client, message);
2025
- return;
2026
- }
2027
- if (op === 'sub') {
2028
- this.handleSubscriptionStatus(client, message);
2029
- return;
2030
- }
2031
- if (op === 'notify') {
2032
- this.handleSubject(client, message);
2033
- return;
2034
- }
2035
- }
2036
- if ('ping' in message) {
2037
- this.handlePing(client, message);
2038
- }
2039
- }
2040
- }
2041
- handleMyTrade(client, message, extendParams = {}) {
2042
- //
2043
- // spot
2044
- //
2045
- // {
2046
- // "action":"push",
2047
- // "ch":"trade.clearing#ltcusdt#1",
2048
- // "data":{
2049
- // "eventType":"trade",
2050
- // "symbol":"ltcusdt",
2051
- // "orderId":"478862728954426",
2052
- // "orderSide":"buy",
2053
- // "orderType":"buy-market",
2054
- // "accountId":44234548,
2055
- // "source":"spot-web",
2056
- // "orderValue":"5.01724137",
2057
- // "orderCreateTime":1645124660365,
2058
- // "orderStatus":"filled",
2059
- // "feeCurrency":"ltc",
2060
- // "tradePrice":"118.89",
2061
- // "tradeVolume":"0.042200701236437042",
2062
- // "aggressor":true,
2063
- // "tradeId":101539740584,
2064
- // "tradeTime":1645124660368,
2065
- // "transactFee":"0.000041778694224073",
2066
- // "feeDeduct":"0",
2067
- // "feeDeductType":""
2068
- // }
2069
- // }
2070
- //
2071
- // contract
2072
- //
2073
- // {
2074
- // "symbol": "ADA/USDT:USDT"
2075
- // "ch": "orders_cross.ada-usdt"
2076
- // "trades": [
2077
- // {
2078
- // "trade_fee":-0.022099447513812154,
2079
- // "fee_asset":"ADA",
2080
- // "trade_id":113913755890,
2081
- // "id":"113913755890-773207641127878656-1",
2082
- // "trade_volume":1,
2083
- // "trade_price":0.0905,
2084
- // "trade_turnover":10,
2085
- // "created_at":1604388667194,
2086
- // "profit":0,
2087
- // "real_profit": 0,
2088
- // "role":"maker"
2089
- // }
2090
- // ],
2091
- // }
2092
- //
2093
- if (this.myTrades === undefined) {
2094
- const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
2095
- this.myTrades = new Cache.ArrayCacheBySymbolById(limit);
2096
- }
2097
- const cachedTrades = this.myTrades;
2098
- const messageHash = this.safeString(message, 'ch');
2099
- if (messageHash !== undefined) {
2100
- const data = this.safeValue(message, 'data');
2101
- if (data !== undefined) {
2102
- const parsed = this.parseWsTrade(data);
2103
- const symbol = this.safeString(parsed, 'symbol');
2104
- if (symbol !== undefined) {
2105
- cachedTrades.append(parsed);
2106
- client.resolve(this.myTrades, messageHash);
2107
- }
2108
- }
2109
- else {
2110
- // this trades object is artificially created
2111
- // in handleOrder
2112
- const rawTrades = this.safeValue(message, 'trades', []);
2113
- const marketId = this.safeValue(message, 'symbol');
2114
- const market = this.market(marketId);
2115
- for (let i = 0; i < rawTrades.length; i++) {
2116
- const trade = rawTrades[i];
2117
- let parsedTrade = this.parseTrade(trade, market);
2118
- // add extra params (side, type, ...) coming from the order
2119
- parsedTrade = this.extend(parsedTrade, extendParams);
2120
- cachedTrades.append(parsedTrade);
2121
- }
2122
- // messageHash here is the orders one, so
2123
- // we have to recreate the trades messageHash = orderMessageHash + ':' + 'trade'
2124
- const tradesHash = messageHash + ':' + 'trade';
2125
- client.resolve(this.myTrades, tradesHash);
2126
- // when we make an global order sub we have to send the channel like this
2127
- // ch = orders_cross.* and we store messageHash = 'orders_cross'
2128
- // however it is returned with the specific order update symbol: ch = orders_cross.btc-usd
2129
- // since this is a global sub, our messageHash does not specify any symbol (ex: orders_cross:trade)
2130
- // so we must remove it
2131
- let genericOrderHash = messageHash.replace('.' + market['lowercaseId'], '');
2132
- genericOrderHash = genericOrderHash.replace('.' + market['lowercaseBaseId'], '');
2133
- const genericTradesHash = genericOrderHash + ':' + 'trade';
2134
- client.resolve(this.myTrades, genericTradesHash);
2135
- }
2136
- }
2137
- }
2138
- parseWsTrade(trade, market = undefined) {
2139
- // spot private
2140
- //
2141
- // {
2142
- // "eventType":"trade",
2143
- // "symbol":"ltcusdt",
2144
- // "orderId":"478862728954426",
2145
- // "orderSide":"buy",
2146
- // "orderType":"buy-market",
2147
- // "accountId":44234548,
2148
- // "source":"spot-web",
2149
- // "orderValue":"5.01724137",
2150
- // "orderCreateTime":1645124660365,
2151
- // "orderStatus":"filled",
2152
- // "feeCurrency":"ltc",
2153
- // "tradePrice":"118.89",
2154
- // "tradeVolume":"0.042200701236437042",
2155
- // "aggressor":true,
2156
- // "tradeId":101539740584,
2157
- // "tradeTime":1645124660368,
2158
- // "transactFee":"0.000041778694224073",
2159
- // "feeDeduct":"0",
2160
- // "feeDeductType":""
2161
- // }
2162
- //
2163
- const symbol = this.safeSymbol(this.safeString(trade, 'symbol'));
2164
- const side = this.safeString2(trade, 'side', 'orderSide');
2165
- const tradeId = this.safeString(trade, 'tradeId');
2166
- const price = this.safeString(trade, 'tradePrice');
2167
- const amount = this.safeString(trade, 'tradeVolume');
2168
- const order = this.safeString(trade, 'orderId');
2169
- const timestamp = this.safeInteger(trade, 'tradeTime');
2170
- market = this.market(symbol);
2171
- const orderType = this.safeString(trade, 'orderType');
2172
- const aggressor = this.safeValue(trade, 'aggressor');
2173
- let takerOrMaker = undefined;
2174
- if (aggressor !== undefined) {
2175
- takerOrMaker = aggressor ? 'taker' : 'maker';
2176
- }
2177
- let type = undefined;
2178
- let orderTypeParts = [];
2179
- if (orderType !== undefined) {
2180
- orderTypeParts = orderType.split('-');
2181
- type = this.safeString(orderTypeParts, 1);
2182
- }
2183
- let fee = undefined;
2184
- const feeCurrency = this.safeCurrencyCode(this.safeString(trade, 'feeCurrency'));
2185
- if (feeCurrency !== undefined) {
2186
- fee = {
2187
- 'cost': this.safeString(trade, 'transactFee'),
2188
- 'currency': feeCurrency,
2189
- };
2190
- }
2191
- return this.safeTrade({
2192
- 'info': trade,
2193
- 'timestamp': timestamp,
2194
- 'datetime': this.iso8601(timestamp),
2195
- 'symbol': symbol,
2196
- 'id': tradeId,
2197
- 'order': order,
2198
- 'type': type,
2199
- 'takerOrMaker': takerOrMaker,
2200
- 'side': side,
2201
- 'price': price,
2202
- 'amount': amount,
2203
- 'cost': undefined,
2204
- 'fee': fee,
2205
- }, market);
2206
- }
2207
- getUrlByMarketType(type, isLinear = true, isPrivate = false) {
2208
- const api = this.safeString(this.options, 'api', 'api');
2209
- const hostname = { 'hostname': this.hostname };
2210
- let hostnameURL = undefined;
2211
- let url = undefined;
2212
- if (type === 'spot') {
2213
- if (isPrivate) {
2214
- hostnameURL = this.urls['api']['ws'][api]['spot']['private'];
2215
- }
2216
- else {
2217
- hostnameURL = this.urls['api']['ws'][api]['spot']['public'];
2218
- }
2219
- url = this.implodeParams(hostnameURL, hostname);
2220
- }
2221
- else {
2222
- const baseUrl = this.urls['api']['ws'][api][type];
2223
- const subTypeUrl = isLinear ? baseUrl['linear'] : baseUrl['inverse'];
2224
- url = isPrivate ? subTypeUrl['private'] : subTypeUrl['public'];
2225
- }
2226
- return url;
2227
- }
2228
- async subscribePublic(url, symbol, messageHash, method = undefined, params = {}) {
2229
- const requestId = this.requestId();
2230
- const request = {
2231
- 'sub': messageHash,
2232
- 'id': requestId,
2233
- };
2234
- const subscription = {
2235
- 'id': requestId,
2236
- 'messageHash': messageHash,
2237
- 'symbol': symbol,
2238
- 'params': params,
2239
- };
2240
- if (method !== undefined) {
2241
- subscription['method'] = method;
2242
- }
2243
- return await this.watch(url, messageHash, this.extend(request, params), messageHash, subscription);
2244
- }
2245
- async subscribePrivate(channel, messageHash, type, subtype, params = {}, subscriptionParams = {}) {
2246
- const requestId = this.requestId();
2247
- const subscription = {
2248
- 'id': requestId,
2249
- 'messageHash': messageHash,
2250
- 'params': params,
2251
- };
2252
- const extendedSubsription = this.extend(subscription, subscriptionParams);
2253
- let request = undefined;
2254
- if (type === 'spot') {
2255
- request = {
2256
- 'action': 'sub',
2257
- 'ch': channel,
2258
- };
2259
- }
2260
- else {
2261
- request = {
2262
- 'op': 'sub',
2263
- 'topic': channel,
2264
- 'cid': requestId,
2265
- };
2266
- }
2267
- const isLinear = subtype === 'linear';
2268
- const url = this.getUrlByMarketType(type, isLinear, true);
2269
- const hostname = (type === 'spot') ? this.urls['hostnames']['spot'] : this.urls['hostnames']['contract'];
2270
- const authParams = {
2271
- 'type': type,
2272
- 'url': url,
2273
- 'hostname': hostname,
2274
- };
2275
- if (type === 'spot') {
2276
- this.options['ws']['gunzip'] = false;
2277
- }
2278
- await this.authenticate(authParams);
2279
- return await this.watch(url, messageHash, this.extend(request, params), channel, extendedSubsription);
2280
- }
2281
- async authenticate(params = {}) {
2282
- const url = this.safeString(params, 'url');
2283
- const hostname = this.safeString(params, 'hostname');
2284
- const type = this.safeString(params, 'type');
2285
- if (url === undefined || hostname === undefined || type === undefined) {
2286
- throw new errors.ArgumentsRequired(this.id + ' authenticate requires a url, hostname and type argument');
2287
- }
2288
- this.checkRequiredCredentials();
2289
- const messageHash = 'authenticated';
2290
- const relativePath = url.replace('wss://' + hostname, '');
2291
- const client = this.client(url);
2292
- const future = client.future(messageHash);
2293
- const authenticated = this.safeValue(client.subscriptions, messageHash);
2294
- if (authenticated === undefined) {
2295
- const timestamp = this.ymdhms(this.milliseconds(), 'T');
2296
- let signatureParams = undefined;
2297
- if (type === 'spot') {
2298
- signatureParams = {
2299
- 'accessKey': this.apiKey,
2300
- 'signatureMethod': 'HmacSHA256',
2301
- 'signatureVersion': '2.1',
2302
- 'timestamp': timestamp,
2303
- };
2304
- }
2305
- else {
2306
- signatureParams = {
2307
- 'AccessKeyId': this.apiKey,
2308
- 'SignatureMethod': 'HmacSHA256',
2309
- 'SignatureVersion': '2',
2310
- 'Timestamp': timestamp,
2311
- };
2312
- }
2313
- signatureParams = this.keysort(signatureParams);
2314
- const auth = this.urlencode(signatureParams);
2315
- const payload = ['GET', hostname, relativePath, auth].join("\n"); // eslint-disable-line quotes
2316
- const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha256.sha256, 'base64');
2317
- let request = undefined;
2318
- if (type === 'spot') {
2319
- const newParams = {
2320
- 'authType': 'api',
2321
- 'accessKey': this.apiKey,
2322
- 'signatureMethod': 'HmacSHA256',
2323
- 'signatureVersion': '2.1',
2324
- 'timestamp': timestamp,
2325
- 'signature': signature,
2326
- };
2327
- request = {
2328
- 'params': newParams,
2329
- 'action': 'req',
2330
- 'ch': 'auth',
2331
- };
2332
- }
2333
- else {
2334
- request = {
2335
- 'op': 'auth',
2336
- 'type': 'api',
2337
- 'AccessKeyId': this.apiKey,
2338
- 'SignatureMethod': 'HmacSHA256',
2339
- 'SignatureVersion': '2',
2340
- 'Timestamp': timestamp,
2341
- 'Signature': signature,
2342
- };
2343
- }
2344
- const requestId = this.requestId();
2345
- const subscription = {
2346
- 'id': requestId,
2347
- 'messageHash': messageHash,
2348
- 'params': params,
2349
- };
2350
- this.watch(url, messageHash, request, messageHash, subscription);
2351
- }
2352
- return future;
2353
- }
2354
14
  }
2355
15
 
2356
16
  module.exports = huobi;