ccxt 4.5.30 → 4.5.32

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 (73) hide show
  1. package/README.md +4 -4
  2. package/dist/ccxt.browser.min.js +18 -18
  3. package/dist/cjs/ccxt.js +6 -4
  4. package/dist/cjs/src/aster.js +3802 -0
  5. package/dist/cjs/src/backpack.js +1 -1
  6. package/dist/cjs/src/base/Exchange.js +35 -2
  7. package/dist/cjs/src/base/ws/WsClient.js +1 -0
  8. package/dist/cjs/src/bigone.js +1 -1
  9. package/dist/cjs/src/binance.js +1 -0
  10. package/dist/cjs/src/bingx.js +73 -0
  11. package/dist/cjs/src/cryptomus.js +1 -1
  12. package/dist/cjs/src/gate.js +52 -6
  13. package/dist/cjs/src/hyperliquid.js +9 -1
  14. package/dist/cjs/src/kucoin.js +63 -64
  15. package/dist/cjs/src/okx.js +14 -5
  16. package/dist/cjs/src/pro/apex.js +2 -2
  17. package/dist/cjs/src/pro/ascendex.js +1 -1
  18. package/dist/cjs/src/pro/aster.js +1046 -0
  19. package/dist/cjs/src/pro/bingx.js +1 -1
  20. package/dist/cjs/src/pro/bybit.js +1 -1
  21. package/dist/cjs/src/pro/cryptocom.js +1 -1
  22. package/dist/cjs/src/pro/dydx.js +1 -1
  23. package/dist/cjs/src/pro/htx.js +1 -1
  24. package/dist/cjs/src/pro/hyperliquid.js +1 -1
  25. package/dist/cjs/src/pro/p2b.js +1 -1
  26. package/dist/cjs/src/pro/toobit.js +1 -1
  27. package/js/ccxt.d.ts +8 -5
  28. package/js/ccxt.js +6 -4
  29. package/js/src/abstract/aster.d.ts +88 -0
  30. package/js/src/abstract/binance.d.ts +1 -0
  31. package/js/src/abstract/binancecoinm.d.ts +1 -0
  32. package/js/src/abstract/binanceus.d.ts +1 -0
  33. package/js/src/abstract/binanceusdm.d.ts +1 -0
  34. package/js/src/abstract/kucoin.d.ts +2 -0
  35. package/js/src/abstract/kucoinfutures.d.ts +2 -0
  36. package/js/src/aster.d.ts +563 -0
  37. package/js/src/aster.js +3801 -0
  38. package/js/src/backpack.js +1 -1
  39. package/js/src/base/Exchange.d.ts +4 -0
  40. package/js/src/base/Exchange.js +35 -1
  41. package/js/src/base/ws/WsClient.js +1 -0
  42. package/js/src/bigone.js +1 -1
  43. package/js/src/binance.d.ts +1 -1
  44. package/js/src/binance.js +1 -0
  45. package/js/src/bingx.d.ts +12 -1
  46. package/js/src/bingx.js +73 -0
  47. package/js/src/cryptomus.js +1 -1
  48. package/js/src/exmo.d.ts +1 -1
  49. package/js/src/gate.js +52 -6
  50. package/js/src/hyperliquid.d.ts +1 -0
  51. package/js/src/hyperliquid.js +9 -1
  52. package/js/src/kucoin.d.ts +5 -3
  53. package/js/src/kucoin.js +63 -64
  54. package/js/src/okx.js +14 -5
  55. package/js/src/pro/apex.js +2 -2
  56. package/js/src/pro/ascendex.js +1 -1
  57. package/js/src/pro/aster.d.ts +273 -0
  58. package/js/src/pro/aster.js +1045 -0
  59. package/js/src/pro/bingx.js +1 -1
  60. package/js/src/pro/bybit.js +1 -1
  61. package/js/src/pro/cryptocom.js +1 -1
  62. package/js/src/pro/dydx.js +1 -1
  63. package/js/src/pro/htx.js +1 -1
  64. package/js/src/pro/hyperliquid.js +1 -1
  65. package/js/src/pro/p2b.js +1 -1
  66. package/js/src/pro/toobit.js +1 -1
  67. package/package.json +1 -1
  68. package/dist/cjs/src/oceanex.js +0 -1125
  69. package/js/src/abstract/oceanex.d.ts +0 -30
  70. package/js/src/oceanex.d.ts +0 -231
  71. package/js/src/oceanex.js +0 -1124
  72. /package/dist/cjs/src/abstract/{oceanex.js → aster.js} +0 -0
  73. /package/js/src/abstract/{oceanex.js → aster.js} +0 -0
@@ -0,0 +1,1045 @@
1
+ // ----------------------------------------------------------------------------
2
+
3
+ // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+ // EDIT THE CORRESPONDENT .ts FILE INSTEAD
6
+
7
+ // ---------------------------------------------------------------------------
8
+ import asterRest from '../aster.js';
9
+ import { ArgumentsRequired } from '../base/errors.js';
10
+ import { ArrayCache, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
11
+ // ---------------------------------------------------------------------------
12
+ export default class aster extends asterRest {
13
+ describe() {
14
+ return this.deepExtend(super.describe(), {
15
+ 'has': {
16
+ 'ws': true,
17
+ 'watchBalance': false,
18
+ 'watchBidsAsks': true,
19
+ 'watchTicker': true,
20
+ 'watchTickers': true,
21
+ 'watchMarkPrice': true,
22
+ 'watchMarkPrices': true,
23
+ 'watchTrades': true,
24
+ 'watchTradesForSymbols': true,
25
+ 'watchOrderBook': true,
26
+ 'watchOrderBookForSymbols': true,
27
+ 'watchOHLCV': true,
28
+ 'watchOHLCVForSymbols': true,
29
+ 'unWatchTicker': true,
30
+ 'unWatchTickers': true,
31
+ 'unWatchMarkPrice': true,
32
+ 'unWatchMarkPrices': true,
33
+ 'unWatchBidsAsks': true,
34
+ 'unWatchTrades': true,
35
+ 'unWatchTradesForSymbols': true,
36
+ 'unWatchOrderBook': true,
37
+ 'unWatchOrderBookForSymbols': true,
38
+ 'unWatchOHLCV': true,
39
+ 'unWatchOHLCVForSymbols': true,
40
+ },
41
+ 'urls': {
42
+ 'api': {
43
+ 'ws': {
44
+ 'spot': 'wss://sstream.asterdex.com/stream',
45
+ 'swap': 'wss://fstream.asterdex.com/stream',
46
+ },
47
+ },
48
+ },
49
+ 'options': {},
50
+ 'streaming': {},
51
+ 'exceptions': {},
52
+ });
53
+ }
54
+ getAccountTypeFromSubscriptions(subscriptions) {
55
+ let accountType = '';
56
+ for (let i = 0; i < subscriptions.length; i++) {
57
+ const subscription = subscriptions[i];
58
+ if ((subscription === 'spot') || (subscription === 'swap')) {
59
+ accountType = subscription;
60
+ break;
61
+ }
62
+ }
63
+ return accountType;
64
+ }
65
+ /**
66
+ * @method
67
+ * @name aster#watchTicker
68
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
69
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#full-ticker-per-symbol
70
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-ticker-streams
71
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
72
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
73
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
74
+ */
75
+ async watchTicker(symbol, params = {}) {
76
+ params['callerMethodName'] = 'watchTicker';
77
+ await this.loadMarkets();
78
+ symbol = this.safeSymbol(symbol);
79
+ const tickers = await this.watchTickers([symbol], params);
80
+ return tickers[symbol];
81
+ }
82
+ /**
83
+ * @method
84
+ * @name aster#unWatchTicker
85
+ * @description unWatches a price ticker
86
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#full-ticker-per-symbol
87
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-ticker-streams
88
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
89
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
90
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
91
+ */
92
+ async unWatchTicker(symbol, params = {}) {
93
+ params['callerMethodName'] = 'unWatchTicker';
94
+ return await this.unWatchTickers([symbol], params);
95
+ }
96
+ /**
97
+ * @method
98
+ * @name aster#watchTickers
99
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
100
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#full-ticker-per-symbol
101
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-ticker-streams
102
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
103
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
104
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
105
+ */
106
+ async watchTickers(symbols = undefined, params = {}) {
107
+ await this.loadMarkets();
108
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
109
+ const firstMarket = this.getMarketFromSymbols(symbols);
110
+ const type = this.safeString(firstMarket, 'type', 'swap');
111
+ const symbolsLength = symbols.length;
112
+ let methodName = undefined;
113
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchTickers');
114
+ params = this.omit(params, 'callerMethodName');
115
+ if (symbolsLength === 0) {
116
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
117
+ }
118
+ const url = this.urls['api']['ws'][type];
119
+ const subscriptionArgs = [];
120
+ const messageHashes = [];
121
+ const request = {
122
+ 'method': 'SUBSCRIBE',
123
+ 'params': subscriptionArgs,
124
+ };
125
+ for (let i = 0; i < symbols.length; i++) {
126
+ const symbol = symbols[i];
127
+ const market = this.market(symbol);
128
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@ticker');
129
+ messageHashes.push('ticker:' + market['symbol']);
130
+ }
131
+ const newTicker = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
132
+ if (this.newUpdates) {
133
+ const result = {};
134
+ result[newTicker['symbol']] = newTicker;
135
+ return result;
136
+ }
137
+ return this.filterByArray(this.tickers, 'symbol', symbols);
138
+ }
139
+ /**
140
+ * @method
141
+ * @name aster#unWatchTickers
142
+ * @description unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
143
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#full-ticker-per-symbol
144
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-ticker-streams
145
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
146
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
147
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
148
+ */
149
+ async unWatchTickers(symbols = undefined, params = {}) {
150
+ await this.loadMarkets();
151
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
152
+ const firstMarket = this.getMarketFromSymbols(symbols);
153
+ const type = this.safeString(firstMarket, 'type', 'swap');
154
+ const symbolsLength = symbols.length;
155
+ let methodName = undefined;
156
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchTickers');
157
+ params = this.omit(params, 'callerMethodName');
158
+ if (symbolsLength === 0) {
159
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
160
+ }
161
+ const url = this.urls['api']['ws'][type];
162
+ const subscriptionArgs = [];
163
+ const messageHashes = [];
164
+ const request = {
165
+ 'method': 'UNSUBSCRIBE',
166
+ 'params': subscriptionArgs,
167
+ };
168
+ for (let i = 0; i < symbols.length; i++) {
169
+ const symbol = symbols[i];
170
+ const market = this.market(symbol);
171
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@ticker');
172
+ messageHashes.push('unsubscribe:ticker:' + market['symbol']);
173
+ }
174
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
175
+ }
176
+ /**
177
+ * @method
178
+ * @name aster#watchMarkPrice
179
+ * @description watches a mark price for a specific market
180
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price-stream
181
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
182
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
183
+ * @param {boolean} [params.use1sFreq] *default is true* if set to true, the mark price will be updated every second, otherwise every 3 seconds
184
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
185
+ */
186
+ async watchMarkPrice(symbol, params = {}) {
187
+ params['callerMethodName'] = 'watchMarkPrice';
188
+ await this.loadMarkets();
189
+ symbol = this.safeSymbol(symbol);
190
+ const tickers = await this.watchMarkPrices([symbol], params);
191
+ return tickers[symbol];
192
+ }
193
+ /**
194
+ * @method
195
+ * @name aster#unWatchMarkPrice
196
+ * @description unWatches a mark price for a specific market
197
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price-stream
198
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
199
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
200
+ * @param {boolean} [params.use1sFreq] *default is true* if set to true, the mark price will be updated every second, otherwise every 3 seconds
201
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
202
+ */
203
+ async unWatchMarkPrice(symbol, params = {}) {
204
+ params['callerMethodName'] = 'unWatchMarkPrice';
205
+ return await this.unWatchMarkPrices([symbol], params);
206
+ }
207
+ /**
208
+ * @method
209
+ * @name aster#watchMarkPrices
210
+ * @description watches the mark price for all markets
211
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price-stream
212
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
213
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
214
+ * @param {boolean} [params.use1sFreq] *default is true* if set to true, the mark price will be updated every second, otherwise every 3 seconds
215
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
216
+ */
217
+ async watchMarkPrices(symbols = undefined, params = {}) {
218
+ await this.loadMarkets();
219
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
220
+ const firstMarket = this.getMarketFromSymbols(symbols);
221
+ const type = this.safeString(firstMarket, 'type', 'swap');
222
+ const symbolsLength = symbols.length;
223
+ let methodName = undefined;
224
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchMarkPrices');
225
+ params = this.omit(params, 'callerMethodName');
226
+ if (symbolsLength === 0) {
227
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
228
+ }
229
+ const url = this.urls['api']['ws'][type];
230
+ const subscriptionArgs = [];
231
+ const messageHashes = [];
232
+ const request = {
233
+ 'method': 'SUBSCRIBE',
234
+ 'params': subscriptionArgs,
235
+ };
236
+ const use1sFreq = this.safeBool(params, 'use1sFreq', true);
237
+ for (let i = 0; i < symbols.length; i++) {
238
+ const symbol = symbols[i];
239
+ const market = this.market(symbol);
240
+ const suffix = (use1sFreq) ? '@1s' : '';
241
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@markPrice' + suffix);
242
+ messageHashes.push('ticker:' + market['symbol']);
243
+ }
244
+ const newTicker = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
245
+ if (this.newUpdates) {
246
+ const result = {};
247
+ result[newTicker['symbol']] = newTicker;
248
+ return result;
249
+ }
250
+ return this.filterByArray(this.tickers, 'symbol', symbols);
251
+ }
252
+ /**
253
+ * @method
254
+ * @name aster#unWatchMarkPrices
255
+ * @description watches the mark price for all markets
256
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price-stream
257
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
258
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
259
+ * @param {boolean} [params.use1sFreq] *default is true* if set to true, the mark price will be updated every second, otherwise every 3 seconds
260
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
261
+ */
262
+ async unWatchMarkPrices(symbols = undefined, params = {}) {
263
+ await this.loadMarkets();
264
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
265
+ const firstMarket = this.getMarketFromSymbols(symbols);
266
+ const type = this.safeString(firstMarket, 'type', 'swap');
267
+ const symbolsLength = symbols.length;
268
+ let methodName = undefined;
269
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchMarkPrices');
270
+ params = this.omit(params, 'callerMethodName');
271
+ if (symbolsLength === 0) {
272
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
273
+ }
274
+ const url = this.urls['api']['ws'][type];
275
+ const subscriptionArgs = [];
276
+ const messageHashes = [];
277
+ const request = {
278
+ 'method': 'UNSUBSCRIBE',
279
+ 'params': subscriptionArgs,
280
+ };
281
+ const use1sFreq = this.safeBool(params, 'use1sFreq', true);
282
+ for (let i = 0; i < symbols.length; i++) {
283
+ const symbol = symbols[i];
284
+ const market = this.market(symbol);
285
+ const suffix = (use1sFreq) ? '@1s' : '';
286
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@markPrice' + suffix);
287
+ messageHashes.push('unsubscribe:ticker:' + market['symbol']);
288
+ }
289
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
290
+ }
291
+ handleTicker(client, message) {
292
+ //
293
+ // {
294
+ // "stream": "trumpusdt@ticker",
295
+ // "data": {
296
+ // "e": "24hrTicker",
297
+ // "E": 1754451187277,
298
+ // "s": "CAKEUSDT",
299
+ // "p": "-0.08800",
300
+ // "P": "-3.361",
301
+ // "w": "2.58095",
302
+ // "c": "2.53000",
303
+ // "Q": "5",
304
+ // "o": "2.61800",
305
+ // "h": "2.64700",
306
+ // "l": "2.52400",
307
+ // "v": "15775",
308
+ // "q": "40714.46000",
309
+ // "O": 1754364780000,
310
+ // "C": 1754451187274,
311
+ // "F": 6571389,
312
+ // "L": 6574507,
313
+ // "n": 3119
314
+ // }
315
+ // }
316
+ // {
317
+ // "stream": "btcusdt@markPrice",
318
+ // "data": {
319
+ // "e": "markPriceUpdate",
320
+ // "E": 1754660466000,
321
+ // "s": "BTCUSDT",
322
+ // "p": "116809.60000000",
323
+ // "P": "116595.54012838",
324
+ // "i": "116836.93534884",
325
+ // "r": "0.00010000",
326
+ // "T": 1754668800000
327
+ // }
328
+ // }
329
+ //
330
+ const subscriptions = client.subscriptions;
331
+ const subscriptionsKeys = Object.keys(subscriptions);
332
+ const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
333
+ const ticker = this.safeDict(message, 'data');
334
+ const parsed = this.parseWsTicker(ticker, marketType);
335
+ const symbol = parsed['symbol'];
336
+ const messageHash = 'ticker:' + symbol;
337
+ this.tickers[symbol] = parsed;
338
+ client.resolve(this.tickers[symbol], messageHash);
339
+ }
340
+ parseWsTicker(message, marketType) {
341
+ const event = this.safeString(message, 'e');
342
+ const part = event.split('@');
343
+ const channel = this.safeString(part, 1);
344
+ const marketId = this.safeString(message, 's');
345
+ const timestamp = this.safeInteger(message, 'E');
346
+ const market = this.safeMarket(marketId, undefined, undefined, marketType);
347
+ const last = this.safeString(message, 'c');
348
+ if (channel === 'markPriceUpdate') {
349
+ return this.safeTicker({
350
+ 'symbol': market['symbol'],
351
+ 'timestamp': timestamp,
352
+ 'datetime': this.iso8601(timestamp),
353
+ 'info': message,
354
+ 'markPrice': this.safeString(message, 'p'),
355
+ 'indexPrice': this.safeString(message, 'i'),
356
+ });
357
+ }
358
+ return this.safeTicker({
359
+ 'symbol': market['symbol'],
360
+ 'timestamp': timestamp,
361
+ 'datetime': this.iso8601(timestamp),
362
+ 'high': this.safeString(message, 'h'),
363
+ 'low': this.safeString(message, 'l'),
364
+ 'bid': undefined,
365
+ 'bidVolume': undefined,
366
+ 'ask': undefined,
367
+ 'askVolume': undefined,
368
+ 'vwap': this.safeString(message, 'w'),
369
+ 'open': this.safeString(message, 'o'),
370
+ 'close': last,
371
+ 'last': last,
372
+ 'previousClose': undefined,
373
+ 'change': this.safeString(message, 'p'),
374
+ 'percentage': this.safeString(message, 'P'),
375
+ 'average': undefined,
376
+ 'baseVolume': this.safeString(message, 'v'),
377
+ 'quoteVolume': this.safeString(message, 'q'),
378
+ 'info': message,
379
+ }, market);
380
+ }
381
+ /**
382
+ * @method
383
+ * @name aster#watchBidsAsks
384
+ * @description watches best bid & ask for symbols
385
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#best-order-book-information-by-symbol
386
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-book-ticker-streams
387
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
388
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
389
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
390
+ */
391
+ async watchBidsAsks(symbols = undefined, params = {}) {
392
+ await this.loadMarkets();
393
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
394
+ const firstMarket = this.getMarketFromSymbols(symbols);
395
+ const type = this.safeString(firstMarket, 'type', 'swap');
396
+ const symbolsLength = symbols.length;
397
+ if (symbolsLength === 0) {
398
+ throw new ArgumentsRequired(this.id + ' watchBidsAsks() requires a non-empty array of symbols');
399
+ }
400
+ const url = this.urls['api']['ws'][type];
401
+ const subscriptionArgs = [];
402
+ const messageHashes = [];
403
+ const request = {
404
+ 'method': 'SUBSCRIBE',
405
+ 'params': subscriptionArgs,
406
+ };
407
+ for (let i = 0; i < symbols.length; i++) {
408
+ const symbol = symbols[i];
409
+ const market = this.market(symbol);
410
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@bookTicker');
411
+ messageHashes.push('bidask:' + market['symbol']);
412
+ }
413
+ const newTicker = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
414
+ if (this.newUpdates) {
415
+ const result = {};
416
+ result[newTicker['symbol']] = newTicker;
417
+ return result;
418
+ }
419
+ return this.filterByArray(this.bidsasks, 'symbol', symbols);
420
+ }
421
+ /**
422
+ * @method
423
+ * @name aster#unWatchBidsAsks
424
+ * @description unWatches best bid & ask for symbols
425
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#best-order-book-information-by-symbol
426
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-book-ticker-streams
427
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
428
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
429
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
430
+ */
431
+ async unWatchBidsAsks(symbols = undefined, params = {}) {
432
+ await this.loadMarkets();
433
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
434
+ const firstMarket = this.getMarketFromSymbols(symbols);
435
+ const type = this.safeString(firstMarket, 'type', 'swap');
436
+ const symbolsLength = symbols.length;
437
+ if (symbolsLength === 0) {
438
+ throw new ArgumentsRequired(this.id + ' unWatchBidsAsks() requires a non-empty array of symbols');
439
+ }
440
+ const url = this.urls['api']['ws'][type];
441
+ const subscriptionArgs = [];
442
+ const messageHashes = [];
443
+ const request = {
444
+ 'method': 'UNSUBSCRIBE',
445
+ 'params': subscriptionArgs,
446
+ };
447
+ for (let i = 0; i < symbols.length; i++) {
448
+ const symbol = symbols[i];
449
+ const market = this.market(symbol);
450
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@bookTicker');
451
+ messageHashes.push('unsubscribe:bidask:' + market['symbol']);
452
+ }
453
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
454
+ }
455
+ handleBidAsk(client, message) {
456
+ //
457
+ // {
458
+ // "stream": "btcusdt@bookTicker",
459
+ // "data": {
460
+ // "e": "bookTicker",
461
+ // "u": 157240846459,
462
+ // "s": "BTCUSDT",
463
+ // "b": "122046.7",
464
+ // "B": "1.084",
465
+ // "a": "122046.8",
466
+ // "A": "0.001",
467
+ // "T": 1754896692922,
468
+ // "E": 1754896692926
469
+ // }
470
+ // }
471
+ //
472
+ const subscriptions = client.subscriptions;
473
+ const subscriptionsKeys = Object.keys(subscriptions);
474
+ const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
475
+ const data = this.safeDict(message, 'data', {});
476
+ const marketId = this.safeString(data, 's');
477
+ const market = this.safeMarket(marketId, undefined, undefined, marketType);
478
+ const ticker = this.parseWsBidAsk(data, market);
479
+ const symbol = ticker['symbol'];
480
+ this.bidsasks[symbol] = ticker;
481
+ const messageHash = 'bidask:' + symbol;
482
+ client.resolve(ticker, messageHash);
483
+ }
484
+ parseWsBidAsk(message, market = undefined) {
485
+ const timestamp = this.safeInteger(message, 'T');
486
+ return this.safeTicker({
487
+ 'symbol': market['symbol'],
488
+ 'timestamp': timestamp,
489
+ 'datetime': this.iso8601(timestamp),
490
+ 'ask': this.safeString(message, 'a'),
491
+ 'askVolume': this.safeString(message, 'A'),
492
+ 'bid': this.safeString(message, 'b'),
493
+ 'bidVolume': this.safeString(message, 'B'),
494
+ 'info': message,
495
+ }, market);
496
+ }
497
+ /**
498
+ * @method
499
+ * @name aster#watchTrades
500
+ * @description watches information on multiple trades made in a market
501
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#collection-transaction-flow
502
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#aggregate-trade-streams
503
+ * @param {string} symbol unified market symbol of the market trades were made in
504
+ * @param {int} [since] the earliest time in ms to fetch trades for
505
+ * @param {int} [limit] the maximum number of trade structures to retrieve
506
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
507
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
508
+ */
509
+ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
510
+ params['callerMethodName'] = 'watchTrades';
511
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
512
+ }
513
+ /**
514
+ * @method
515
+ * @name aster#unWatchTrades
516
+ * @description unsubscribe from the trades channel
517
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#collection-transaction-flow
518
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#aggregate-trade-streams
519
+ * @param {string} symbol unified market symbol of the market trades were made in
520
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
521
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
522
+ */
523
+ async unWatchTrades(symbol, params = {}) {
524
+ params['callerMethodName'] = 'unWatchTrades';
525
+ return await this.unWatchTradesForSymbols([symbol], params);
526
+ }
527
+ /**
528
+ * @method
529
+ * @name aster#watchTradesForSymbols
530
+ * @description get the list of most recent trades for a list of symbols
531
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#collection-transaction-flow
532
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#aggregate-trade-streams
533
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
534
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
535
+ * @param {int} [limit] the maximum amount of trades to fetch
536
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
537
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
538
+ */
539
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
540
+ await this.loadMarkets();
541
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
542
+ const firstMarket = this.getMarketFromSymbols(symbols);
543
+ const type = this.safeString(firstMarket, 'type', 'swap');
544
+ const symbolsLength = symbols.length;
545
+ let methodName = undefined;
546
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchTradesForSymbols');
547
+ params = this.omit(params, 'callerMethodName');
548
+ if (symbolsLength === 0) {
549
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
550
+ }
551
+ const url = this.urls['api']['ws'][type];
552
+ const subscriptionArgs = [];
553
+ const messageHashes = [];
554
+ const request = {
555
+ 'method': 'SUBSCRIBE',
556
+ 'params': subscriptionArgs,
557
+ };
558
+ for (let i = 0; i < symbols.length; i++) {
559
+ const symbol = symbols[i];
560
+ const market = this.market(symbol);
561
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@aggTrade');
562
+ messageHashes.push('trade:' + market['symbol']);
563
+ }
564
+ const trades = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
565
+ if (this.newUpdates) {
566
+ const first = this.safeValue(trades, 0);
567
+ const tradeSymbol = this.safeString(first, 'symbol');
568
+ limit = trades.getLimit(tradeSymbol, limit);
569
+ }
570
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
571
+ }
572
+ /**
573
+ * @method
574
+ * @name aster#unWatchTradesForSymbols
575
+ * @description unsubscribe from the trades channel
576
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#collection-transaction-flow
577
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#aggregate-trade-streams
578
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
579
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
580
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
581
+ */
582
+ async unWatchTradesForSymbols(symbols, params = {}) {
583
+ await this.loadMarkets();
584
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
585
+ const firstMarket = this.getMarketFromSymbols(symbols);
586
+ const type = this.safeString(firstMarket, 'type', 'swap');
587
+ const symbolsLength = symbols.length;
588
+ let methodName = undefined;
589
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchTradesForSymbols');
590
+ params = this.omit(params, 'callerMethodName');
591
+ if (symbolsLength === 0) {
592
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
593
+ }
594
+ const url = this.urls['api']['ws'][type];
595
+ const subscriptionArgs = [];
596
+ const messageHashes = [];
597
+ const request = {
598
+ 'method': 'UNSUBSCRIBE',
599
+ 'params': subscriptionArgs,
600
+ };
601
+ for (let i = 0; i < symbols.length; i++) {
602
+ const symbol = symbols[i];
603
+ const market = this.market(symbol);
604
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@aggTrade');
605
+ messageHashes.push('unsubscribe:trade:' + market['symbol']);
606
+ }
607
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
608
+ }
609
+ handleTrade(client, message) {
610
+ //
611
+ // {
612
+ // "stream": "btcusdt@aggTrade",
613
+ // "data": {
614
+ // "e": "aggTrade",
615
+ // "E": 1754551358681,
616
+ // "a": 20505890,
617
+ // "s": "BTCUSDT",
618
+ // "p": "114783.7",
619
+ // "q": "0.020",
620
+ // "f": 26024678,
621
+ // "l": 26024682,
622
+ // "T": 1754551358528,
623
+ // "m": false
624
+ // }
625
+ // }
626
+ //
627
+ const subscriptions = client.subscriptions;
628
+ const subscriptionsKeys = Object.keys(subscriptions);
629
+ const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
630
+ const trade = this.safeDict(message, 'data');
631
+ const marketId = this.safeString(trade, 's');
632
+ const market = this.safeMarket(marketId, undefined, undefined, marketType);
633
+ const parsed = this.parseWsTrade(trade, market);
634
+ const symbol = parsed['symbol'];
635
+ let stored = this.safeValue(this.trades, symbol);
636
+ if (stored === undefined) {
637
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
638
+ stored = new ArrayCache(limit);
639
+ this.trades[symbol] = stored;
640
+ }
641
+ stored.append(parsed);
642
+ const messageHash = 'trade' + ':' + symbol;
643
+ client.resolve(stored, messageHash);
644
+ }
645
+ parseWsTrade(trade, market = undefined) {
646
+ const timestamp = this.safeInteger(trade, 'T');
647
+ const symbol = market['symbol'];
648
+ const amountString = this.safeString(trade, 'q');
649
+ const priceString = this.safeString(trade, 'p');
650
+ const isMaker = this.safeBool(trade, 'm');
651
+ let takerOrMaker = undefined;
652
+ if (isMaker !== undefined) {
653
+ takerOrMaker = isMaker ? 'maker' : 'taker';
654
+ }
655
+ return this.safeTrade({
656
+ 'id': this.safeString(trade, 'a'),
657
+ 'info': trade,
658
+ 'timestamp': timestamp,
659
+ 'datetime': this.iso8601(timestamp),
660
+ 'symbol': symbol,
661
+ 'order': undefined,
662
+ 'type': undefined,
663
+ 'side': undefined,
664
+ 'takerOrMaker': takerOrMaker,
665
+ 'price': priceString,
666
+ 'amount': amountString,
667
+ 'cost': undefined,
668
+ 'fee': undefined,
669
+ }, market);
670
+ }
671
+ /**
672
+ * @method
673
+ * @name aster#watchOrderBook
674
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
675
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#limited-depth-information
676
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#partial-book-depth-streams
677
+ * @param {string} symbol unified symbol of the market to fetch the order book for
678
+ * @param {int} [limit] the maximum amount of order book entries to return.
679
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
680
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
681
+ */
682
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
683
+ params['callerMethodName'] = 'watchOrderBook';
684
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
685
+ }
686
+ /**
687
+ * @method
688
+ * @name aster#unWatchOrderBook
689
+ * @description unsubscribe from the orderbook channel
690
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#limited-depth-information
691
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#partial-book-depth-streams
692
+ * @param {string} symbol symbol of the market to unwatch the trades for
693
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
694
+ * @param {int} [params.limit] orderbook limit, default is undefined
695
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
696
+ */
697
+ async unWatchOrderBook(symbol, params = {}) {
698
+ params['callerMethodName'] = 'unWatchOrderBook';
699
+ return await this.unWatchOrderBookForSymbols([symbol], params);
700
+ }
701
+ /**
702
+ * @method
703
+ * @name aster#watchOrderBookForSymbols
704
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
705
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#limited-depth-information
706
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#partial-book-depth-streams
707
+ * @param {string[]} symbols unified array of symbols
708
+ * @param {int} [limit] the maximum amount of order book entries to return.
709
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
710
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
711
+ */
712
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
713
+ await this.loadMarkets();
714
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
715
+ const firstMarket = this.getMarketFromSymbols(symbols);
716
+ const type = this.safeString(firstMarket, 'type', 'swap');
717
+ const symbolsLength = symbols.length;
718
+ let methodName = undefined;
719
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchOrderBookForSymbols');
720
+ params = this.omit(params, 'callerMethodName');
721
+ if (symbolsLength === 0) {
722
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
723
+ }
724
+ const url = this.urls['api']['ws'][type];
725
+ const subscriptionArgs = [];
726
+ const messageHashes = [];
727
+ const request = {
728
+ 'method': 'SUBSCRIBE',
729
+ 'params': subscriptionArgs,
730
+ };
731
+ if (limit === undefined || (limit !== 5 && limit !== 10 && limit !== 20)) {
732
+ limit = 20;
733
+ }
734
+ for (let i = 0; i < symbols.length; i++) {
735
+ const symbol = symbols[i];
736
+ const market = this.market(symbol);
737
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@depth' + limit);
738
+ messageHashes.push('orderbook:' + market['symbol']);
739
+ }
740
+ const orderbook = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
741
+ return orderbook.limit();
742
+ }
743
+ /**
744
+ * @method
745
+ * @name aster#unWatchOrderBookForSymbols
746
+ * @description unsubscribe from the orderbook channel
747
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#limited-depth-information
748
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#partial-book-depth-streams
749
+ * @param {string[]} symbols unified symbol of the market to unwatch the trades for
750
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
751
+ * @param {int} [params.limit] orderbook limit, default is undefined
752
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
753
+ */
754
+ async unWatchOrderBookForSymbols(symbols, params = {}) {
755
+ await this.loadMarkets();
756
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
757
+ const firstMarket = this.getMarketFromSymbols(symbols);
758
+ const type = this.safeString(firstMarket, 'type', 'swap');
759
+ const symbolsLength = symbols.length;
760
+ let methodName = undefined;
761
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchOrderBookForSymbols');
762
+ params = this.omit(params, 'callerMethodName');
763
+ if (symbolsLength === 0) {
764
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
765
+ }
766
+ const url = this.urls['api']['ws'][type];
767
+ const subscriptionArgs = [];
768
+ const messageHashes = [];
769
+ const request = {
770
+ 'method': 'UNSUBSCRIBE',
771
+ 'params': subscriptionArgs,
772
+ };
773
+ let limit = this.safeNumber(params, 'limit');
774
+ params = this.omit(params, 'limit');
775
+ if (limit === undefined || (limit !== 5 && limit !== 10 && limit !== 20)) {
776
+ limit = 20;
777
+ }
778
+ for (let i = 0; i < symbols.length; i++) {
779
+ const symbol = symbols[i];
780
+ const market = this.market(symbol);
781
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@depth' + limit);
782
+ messageHashes.push('unsubscribe:orderbook:' + market['symbol']);
783
+ }
784
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
785
+ }
786
+ handleOrderBook(client, message) {
787
+ //
788
+ // {
789
+ // "stream": "btcusdt@depth20",
790
+ // "data": {
791
+ // "e": "depthUpdate",
792
+ // "E": 1754556878284,
793
+ // "T": 1754556878031,
794
+ // "s": "BTCUSDT",
795
+ // "U": 156391349814,
796
+ // "u": 156391349814,
797
+ // "pu": 156391348236,
798
+ // "b": [
799
+ // [
800
+ // "114988.3",
801
+ // "0.147"
802
+ // ]
803
+ // ],
804
+ // "a": [
805
+ // [
806
+ // "114988.4",
807
+ // "1.060"
808
+ // ]
809
+ // ]
810
+ // }
811
+ // }
812
+ //
813
+ const subscriptions = client.subscriptions;
814
+ const subscriptionsKeys = Object.keys(subscriptions);
815
+ const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
816
+ const data = this.safeDict(message, 'data');
817
+ const marketId = this.safeString(data, 's');
818
+ const timestamp = this.safeInteger(data, 'T');
819
+ const market = this.safeMarket(marketId, undefined, undefined, marketType);
820
+ const symbol = market['symbol'];
821
+ if (!(symbol in this.orderbooks)) {
822
+ this.orderbooks[symbol] = this.orderBook();
823
+ }
824
+ const orderbook = this.orderbooks[symbol];
825
+ const snapshot = this.parseOrderBook(data, symbol, timestamp, 'b', 'a');
826
+ orderbook.reset(snapshot);
827
+ const messageHash = 'orderbook' + ':' + symbol;
828
+ this.orderbooks[symbol] = orderbook;
829
+ client.resolve(orderbook, messageHash);
830
+ }
831
+ /**
832
+ * @method
833
+ * @name aster#watchOHLCV
834
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
835
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-streams
836
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-streams
837
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
838
+ * @param {string} timeframe the length of time each candle represents
839
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
840
+ * @param {int} [limit] the maximum amount of candles to fetch
841
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
842
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
843
+ */
844
+ async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
845
+ params['callerMethodName'] = 'watchOHLCV';
846
+ await this.loadMarkets();
847
+ symbol = this.safeSymbol(symbol);
848
+ const result = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, params);
849
+ return result[symbol][timeframe];
850
+ }
851
+ /**
852
+ * @method
853
+ * @name aster#unWatchOHLCV
854
+ * @description unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
855
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-streams
856
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-streams
857
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
858
+ * @param {string} timeframe the length of time each candle represents
859
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
860
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
861
+ */
862
+ async unWatchOHLCV(symbol, timeframe = '1m', params = {}) {
863
+ params['callerMethodName'] = 'unWatchOHLCV';
864
+ return await this.unWatchOHLCVForSymbols([[symbol, timeframe]], params);
865
+ }
866
+ /**
867
+ * @method
868
+ * @name aster#watchOHLCVForSymbols
869
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
870
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-streams
871
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-streams
872
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
873
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
874
+ * @param {int} [limit] the maximum amount of candles to fetch
875
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
876
+ * @returns {object} A list of candles ordered as timestamp, open, high, low, close, volume
877
+ */
878
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
879
+ await this.loadMarkets();
880
+ const symbolsLength = symbolsAndTimeframes.length;
881
+ let methodName = undefined;
882
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchOHLCVForSymbols');
883
+ params = this.omit(params, 'callerMethodName');
884
+ if (symbolsLength === 0) {
885
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
886
+ }
887
+ const symbols = this.getListFromObjectValues(symbolsAndTimeframes, 0);
888
+ const marketSymbols = this.marketSymbols(symbols, undefined, false, true, true);
889
+ const firstMarket = this.market(marketSymbols[0]);
890
+ const type = this.safeString(firstMarket, 'type', 'swap');
891
+ const url = this.urls['api']['ws'][type];
892
+ const subscriptionArgs = [];
893
+ const messageHashes = [];
894
+ const request = {
895
+ 'method': 'SUBSCRIBE',
896
+ 'params': subscriptionArgs,
897
+ };
898
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
899
+ const data = symbolsAndTimeframes[i];
900
+ let symbolString = this.safeString(data, 0);
901
+ const market = this.market(symbolString);
902
+ symbolString = market['symbol'];
903
+ const unfiedTimeframe = this.safeString(data, 1);
904
+ const timeframeId = this.safeString(this.timeframes, unfiedTimeframe, unfiedTimeframe);
905
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@kline_' + timeframeId);
906
+ messageHashes.push('ohlcv:' + market['symbol'] + ':' + unfiedTimeframe);
907
+ }
908
+ const [symbol, timeframe, stored] = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
909
+ if (this.newUpdates) {
910
+ limit = stored.getLimit(symbol, limit);
911
+ }
912
+ const filtered = this.filterBySinceLimit(stored, since, limit, 0, true);
913
+ return this.createOHLCVObject(symbol, timeframe, filtered);
914
+ }
915
+ /**
916
+ * @method
917
+ * @name aster#unWatchOHLCVForSymbols
918
+ * @description unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
919
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-streams
920
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-streams
921
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
922
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
923
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
924
+ */
925
+ async unWatchOHLCVForSymbols(symbolsAndTimeframes, params = {}) {
926
+ await this.loadMarkets();
927
+ const symbolsLength = symbolsAndTimeframes.length;
928
+ let methodName = undefined;
929
+ [methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchOHLCVForSymbols');
930
+ params = this.omit(params, 'callerMethodName');
931
+ if (symbolsLength === 0) {
932
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
933
+ }
934
+ const symbols = this.getListFromObjectValues(symbolsAndTimeframes, 0);
935
+ const marketSymbols = this.marketSymbols(symbols, undefined, false, true, true);
936
+ const firstMarket = this.market(marketSymbols[0]);
937
+ const type = this.safeString(firstMarket, 'type', 'swap');
938
+ const url = this.urls['api']['ws'][type];
939
+ const subscriptionArgs = [];
940
+ const messageHashes = [];
941
+ const request = {
942
+ 'method': 'UNSUBSCRIBE',
943
+ 'params': subscriptionArgs,
944
+ };
945
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
946
+ const data = symbolsAndTimeframes[i];
947
+ let symbolString = this.safeString(data, 0);
948
+ const market = this.market(symbolString);
949
+ symbolString = market['symbol'];
950
+ const unfiedTimeframe = this.safeString(data, 1);
951
+ const timeframeId = this.safeString(this.timeframes, unfiedTimeframe, unfiedTimeframe);
952
+ subscriptionArgs.push(this.safeStringLower(market, 'id') + '@kline_' + timeframeId);
953
+ messageHashes.push('unsubscribe:ohlcv:' + market['symbol'] + ':' + unfiedTimeframe);
954
+ }
955
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
956
+ }
957
+ handleOHLCV(client, message) {
958
+ //
959
+ // {
960
+ // "stream": "btcusdt@kline_1m",
961
+ // "data": {
962
+ // "e": "kline",
963
+ // "E": 1754655777119,
964
+ // "s": "BTCUSDT",
965
+ // "k": {
966
+ // "t": 1754655720000,
967
+ // "T": 1754655779999,
968
+ // "s": "BTCUSDT",
969
+ // "i": "1m",
970
+ // "f": 26032629,
971
+ // "L": 26032629,
972
+ // "o": "116546.9",
973
+ // "c": "116546.9",
974
+ // "h": "116546.9",
975
+ // "l": "116546.9",
976
+ // "v": "0.011",
977
+ // "n": 1,
978
+ // "x": false,
979
+ // "q": "1282.0159",
980
+ // "V": "0.000",
981
+ // "Q": "0.0000",
982
+ // "B": "0"
983
+ // }
984
+ // }
985
+ // }
986
+ //
987
+ const subscriptions = client.subscriptions;
988
+ const subscriptionsKeys = Object.keys(subscriptions);
989
+ const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
990
+ const data = this.safeDict(message, 'data');
991
+ const marketId = this.safeString(data, 's');
992
+ const market = this.safeMarket(marketId, undefined, undefined, marketType);
993
+ const symbol = market['symbol'];
994
+ const kline = this.safeDict(data, 'k');
995
+ const timeframeId = this.safeString(kline, 'i');
996
+ const timeframe = this.findTimeframe(timeframeId);
997
+ const ohlcvsByTimeframe = this.safeValue(this.ohlcvs, symbol);
998
+ if (ohlcvsByTimeframe === undefined) {
999
+ this.ohlcvs[symbol] = {};
1000
+ }
1001
+ if (this.safeValue(ohlcvsByTimeframe, timeframe) === undefined) {
1002
+ const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
1003
+ this.ohlcvs[symbol][timeframe] = new ArrayCacheByTimestamp(limit);
1004
+ }
1005
+ const stored = this.ohlcvs[symbol][timeframe];
1006
+ const parsed = this.parseWsOHLCV(kline);
1007
+ stored.append(parsed);
1008
+ const messageHash = 'ohlcv:' + symbol + ':' + timeframe;
1009
+ const resolveData = [symbol, timeframe, stored];
1010
+ client.resolve(resolveData, messageHash);
1011
+ }
1012
+ parseWsOHLCV(ohlcv, market = undefined) {
1013
+ return [
1014
+ this.safeInteger(ohlcv, 't'),
1015
+ this.safeNumber(ohlcv, 'o'),
1016
+ this.safeNumber(ohlcv, 'h'),
1017
+ this.safeNumber(ohlcv, 'l'),
1018
+ this.safeNumber(ohlcv, 'c'),
1019
+ this.safeNumber(ohlcv, 'v'),
1020
+ ];
1021
+ }
1022
+ handleMessage(client, message) {
1023
+ const stream = this.safeString(message, 'stream');
1024
+ if (stream !== undefined) {
1025
+ const part = stream.split('@');
1026
+ let topic = this.safeString(part, 1, '');
1027
+ const part2 = topic.split('_');
1028
+ topic = this.safeString(part2, 0, '');
1029
+ const methods = {
1030
+ 'ticker': this.handleTicker,
1031
+ 'aggTrade': this.handleTrade,
1032
+ 'depth5': this.handleOrderBook,
1033
+ 'depth10': this.handleOrderBook,
1034
+ 'depth20': this.handleOrderBook,
1035
+ 'kline': this.handleOHLCV,
1036
+ 'markPrice': this.handleTicker,
1037
+ 'bookTicker': this.handleBidAsk,
1038
+ };
1039
+ const method = this.safeValue(methods, topic);
1040
+ if (method !== undefined) {
1041
+ method.call(this, client, message);
1042
+ }
1043
+ }
1044
+ }
1045
+ }