ccxt 4.5.45 → 4.5.47

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 (91) hide show
  1. package/README.md +5 -6
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +1 -6
  4. package/dist/cjs/src/aftermath.js +1 -1
  5. package/dist/cjs/src/backpack.js +1 -1
  6. package/dist/cjs/src/base/Exchange.js +27 -0
  7. package/dist/cjs/src/binance.js +23 -17
  8. package/dist/cjs/src/bitfinex.js +6 -11
  9. package/dist/cjs/src/bitget.js +9 -4
  10. package/dist/cjs/src/bitmart.js +144 -21
  11. package/dist/cjs/src/bitmex.js +46 -0
  12. package/dist/cjs/src/bitstamp.js +14 -1
  13. package/dist/cjs/src/bittrade.js +1 -1
  14. package/dist/cjs/src/blofin.js +137 -29
  15. package/dist/cjs/src/bybit.js +58 -56
  16. package/dist/cjs/src/bydfi.js +102 -100
  17. package/dist/cjs/src/gate.js +37 -2
  18. package/dist/cjs/src/hollaex.js +1 -1
  19. package/dist/cjs/src/kraken.js +39 -29
  20. package/dist/cjs/src/kucoin.js +2161 -462
  21. package/dist/cjs/src/lighter.js +2 -2
  22. package/dist/cjs/src/okx.js +75 -58
  23. package/dist/cjs/src/paradex.js +2 -6
  24. package/dist/cjs/src/pro/bittrade.js +4 -0
  25. package/dist/cjs/src/pro/bydfi.js +19 -19
  26. package/dist/cjs/src/pro/gate.js +79 -54
  27. package/dist/cjs/src/pro/grvt.js +6 -4
  28. package/dist/cjs/src/pro/htx.js +4 -4
  29. package/dist/cjs/src/pro/lighter.js +1 -1
  30. package/dist/cjs/src/pro/okx.js +1 -1
  31. package/dist/cjs/src/whitebit.js +21 -2
  32. package/index.d.cts +2 -0
  33. package/js/ccxt.d.ts +2 -8
  34. package/js/ccxt.js +2 -6
  35. package/js/src/abstract/bitmart.d.ts +7 -0
  36. package/js/src/abstract/blofin.d.ts +28 -12
  37. package/js/src/abstract/bydfi.d.ts +29 -29
  38. package/js/src/abstract/kraken.d.ts +36 -29
  39. package/js/src/abstract/kucoin.d.ts +2 -0
  40. package/js/src/abstract/kucoinfutures.d.ts +2 -0
  41. package/js/src/aftermath.js +1 -1
  42. package/js/src/backpack.js +1 -1
  43. package/js/src/base/Exchange.d.ts +2 -0
  44. package/js/src/base/Exchange.js +27 -0
  45. package/js/src/binance.js +23 -17
  46. package/js/src/bitfinex.js +6 -11
  47. package/js/src/bitget.d.ts +1 -1
  48. package/js/src/bitget.js +9 -4
  49. package/js/src/bitmart.d.ts +18 -4
  50. package/js/src/bitmart.js +144 -21
  51. package/js/src/bitmex.d.ts +12 -0
  52. package/js/src/bitmex.js +46 -0
  53. package/js/src/bitstamp.js +14 -1
  54. package/js/src/bittrade.js +1 -1
  55. package/js/src/blofin.d.ts +2 -0
  56. package/js/src/blofin.js +137 -29
  57. package/js/src/bybit.d.ts +1 -0
  58. package/js/src/bybit.js +58 -56
  59. package/js/src/bydfi.d.ts +31 -31
  60. package/js/src/bydfi.js +102 -100
  61. package/js/src/gate.js +37 -2
  62. package/js/src/hollaex.js +1 -1
  63. package/js/src/kraken.js +39 -29
  64. package/js/src/kucoin.d.ts +249 -8
  65. package/js/src/kucoin.js +2161 -462
  66. package/js/src/lighter.js +2 -2
  67. package/js/src/okx.d.ts +1 -0
  68. package/js/src/okx.js +75 -58
  69. package/js/src/paradex.d.ts +0 -1
  70. package/js/src/paradex.js +2 -6
  71. package/js/src/pro/bittrade.js +4 -0
  72. package/js/src/pro/bydfi.d.ts +18 -18
  73. package/js/src/pro/bydfi.js +19 -19
  74. package/js/src/pro/gate.d.ts +2 -2
  75. package/js/src/pro/gate.js +79 -54
  76. package/js/src/pro/grvt.js +6 -4
  77. package/js/src/pro/htx.js +4 -4
  78. package/js/src/pro/lighter.js +1 -1
  79. package/js/src/pro/okx.js +1 -1
  80. package/js/src/whitebit.d.ts +1 -1
  81. package/js/src/whitebit.js +21 -2
  82. package/package.json +2 -2
  83. package/dist/cjs/src/abstract/coincatch.js +0 -11
  84. package/dist/cjs/src/coincatch.js +0 -5495
  85. package/dist/cjs/src/pro/coincatch.js +0 -1563
  86. package/js/src/abstract/coincatch.d.ts +0 -97
  87. package/js/src/abstract/coincatch.js +0 -5
  88. package/js/src/coincatch.d.ts +0 -788
  89. package/js/src/coincatch.js +0 -5488
  90. package/js/src/pro/coincatch.d.ts +0 -207
  91. package/js/src/pro/coincatch.js +0 -1556
@@ -1,1563 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var coincatch$1 = require('../coincatch.js');
6
- var errors = require('../base/errors.js');
7
- var Precise = require('../base/Precise.js');
8
- var sha256 = require('../static_dependencies/noble-hashes/sha256.js');
9
- var Cache = require('../base/ws/Cache.js');
10
-
11
- // ---------------------------------------------------------------------------
12
- // ---------------------------------------------------------------------------
13
- class coincatch extends coincatch$1["default"] {
14
- describe() {
15
- return this.deepExtend(super.describe(), {
16
- 'has': {
17
- 'ws': true,
18
- 'watchTrades': true,
19
- 'watchTradesForSymbols': true,
20
- 'watchOrderBook': true,
21
- 'watchOrderBookForSymbols': true,
22
- 'watchOHLCV': true,
23
- 'watchOHLCVForSymbols': false,
24
- 'watchOrders': true,
25
- 'watchMyTrades': false,
26
- 'watchTicker': true,
27
- 'watchTickers': true,
28
- 'watchBalance': true,
29
- 'watchPositions': true,
30
- },
31
- 'urls': {
32
- 'api': {
33
- 'ws': {
34
- 'public': 'wss://ws.coincatch.com/public/v1/stream',
35
- 'private': 'wss://ws.coincatch.com/private/v1/stream',
36
- },
37
- },
38
- },
39
- 'options': {
40
- 'tradesLimit': 1000,
41
- 'OHLCVLimit': 200,
42
- 'timeframesForWs': {
43
- '1m': '1m',
44
- '5m': '5m',
45
- '15m': '15m',
46
- '30m': '30m',
47
- '1h': '1H',
48
- '4h': '4H',
49
- '12h': '12H',
50
- '1d': '1D',
51
- '1w': '1W',
52
- },
53
- 'watchOrderBook': {
54
- 'checksum': true,
55
- },
56
- },
57
- 'streaming': {
58
- 'ping': this.ping,
59
- },
60
- 'exceptions': {
61
- 'ws': {
62
- 'exact': {
63
- '30001': errors.BadRequest,
64
- '30002': errors.AuthenticationError,
65
- '30003': errors.BadRequest,
66
- '30004': errors.AuthenticationError,
67
- '30005': errors.AuthenticationError,
68
- '30006': errors.RateLimitExceeded,
69
- '30007': errors.RateLimitExceeded,
70
- '30011': errors.AuthenticationError,
71
- '30012': errors.AuthenticationError,
72
- '30013': errors.AuthenticationError,
73
- '30014': errors.BadRequest,
74
- '30015': errors.AuthenticationError, // { event: 'error', code: 30015, msg: 'Invalid sign' }
75
- },
76
- 'broad': {},
77
- },
78
- },
79
- });
80
- }
81
- getMarketFromArg(entry) {
82
- const instId = this.safeString(entry, 'instId');
83
- const instType = this.safeString(entry, 'instType');
84
- const baseAndQuote = this.parseSpotMarketId(instId);
85
- const baseId = baseAndQuote['baseId'];
86
- const quoteId = baseAndQuote['quoteId'];
87
- let suffix = '_SPBL'; // spot suffix
88
- if (instType === 'mc') {
89
- if (quoteId === 'USD') {
90
- suffix = '_DMCBL';
91
- }
92
- else {
93
- suffix = '_UMCBL';
94
- }
95
- }
96
- const marketId = this.safeCurrencyCode(baseId) + this.safeCurrencyCode(quoteId) + suffix;
97
- return this.safeMarketCustom(marketId);
98
- }
99
- async authenticate(params = {}) {
100
- this.checkRequiredCredentials();
101
- const url = this.urls['api']['ws']['private'];
102
- const client = this.client(url);
103
- const messageHash = 'authenticated';
104
- const future = client.reusableFuture(messageHash);
105
- const authenticated = this.safeValue(client.subscriptions, messageHash);
106
- if (authenticated === undefined) {
107
- const timestamp = this.seconds().toString();
108
- const auth = timestamp + 'GET' + '/user/verify';
109
- const signature = this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256, 'base64');
110
- const operation = 'login';
111
- const request = {
112
- 'op': operation,
113
- 'args': [
114
- {
115
- 'apiKey': this.apiKey,
116
- 'passphrase': this.password,
117
- 'timestamp': timestamp,
118
- 'sign': signature,
119
- },
120
- ],
121
- };
122
- const message = this.extend(request, params);
123
- this.watch(url, messageHash, message, messageHash);
124
- }
125
- return await future;
126
- }
127
- async watchPublic(messageHash, subscribeHash, args, params = {}) {
128
- const url = this.urls['api']['ws']['public'];
129
- const request = {
130
- 'op': 'subscribe',
131
- 'args': [args],
132
- };
133
- const message = this.extend(request, params);
134
- return await this.watch(url, messageHash, message, subscribeHash);
135
- }
136
- async unWatchPublic(messageHash, args, params = {}) {
137
- const url = this.urls['api']['ws']['public'];
138
- const request = {
139
- 'op': 'unsubscribe',
140
- 'args': [args],
141
- };
142
- const message = this.extend(request, params);
143
- return await this.watch(url, messageHash, message, messageHash);
144
- }
145
- async watchPrivate(messageHash, subscribeHash, args, params = {}) {
146
- await this.authenticate();
147
- const url = this.urls['api']['ws']['private'];
148
- const request = {
149
- 'op': 'subscribe',
150
- 'args': [args],
151
- };
152
- const message = this.extend(request, params);
153
- return await this.watch(url, messageHash, message, subscribeHash);
154
- }
155
- async watchPrivateMultiple(messageHashes, subscribeHashes, args, params = {}) {
156
- await this.authenticate();
157
- const url = this.urls['api']['ws']['private'];
158
- const request = {
159
- 'op': 'subscribe',
160
- 'args': args,
161
- };
162
- const message = this.extend(request, params);
163
- return await this.watchMultiple(url, messageHashes, message, subscribeHashes);
164
- }
165
- handleAuthenticate(client, message) {
166
- //
167
- // { event: "login", code: 0 }
168
- //
169
- const messageHash = 'authenticated';
170
- const future = this.safeValue(client.futures, messageHash);
171
- future.resolve(true);
172
- }
173
- async watchPublicMultiple(messageHashes, subscribeHashes, argsArray, params = {}) {
174
- const url = this.urls['api']['ws']['public'];
175
- const request = {
176
- 'op': 'subscribe',
177
- 'args': argsArray,
178
- };
179
- const message = this.extend(request, params);
180
- return await this.watchMultiple(url, messageHashes, message, subscribeHashes);
181
- }
182
- async unWatchChannel(symbol, channel, messageHashTopic, params = {}) {
183
- await this.loadMarkets();
184
- const market = this.market(symbol);
185
- const [instType, instId] = this.getPublicInstTypeAndId(market);
186
- const messageHash = 'unsubscribe:' + messageHashTopic + ':' + symbol;
187
- const args = {
188
- 'instType': instType,
189
- 'channel': channel,
190
- 'instId': instId,
191
- };
192
- return await this.unWatchPublic(messageHash, args, params);
193
- }
194
- getPublicInstTypeAndId(market) {
195
- const instId = market['baseId'] + market['quoteId'];
196
- let instType = undefined;
197
- if (market['spot']) {
198
- instType = 'SP';
199
- }
200
- else if (market['swap']) {
201
- instType = 'MC';
202
- }
203
- else {
204
- throw new errors.NotSupported(this.id + ' supports only spot and swap markets');
205
- }
206
- return [instType, instId];
207
- }
208
- handleDMCBLMarketByMessageHashes(market, hash, client, timeframe = undefined) {
209
- const marketId = market['id'];
210
- const messageHashes = this.findMessageHashes(client, hash);
211
- // the exchange counts DMCBL markets as the same market with different quote currencies
212
- // for example symbols ETHUSD:ETH and ETH/USD:BTC both have the same marketId ETHUSD_DMCBL
213
- // we need to check all markets with the same marketId to find the correct market that is in messageHashes
214
- const marketsWithCurrentId = this.safeList(this.markets_by_id, marketId, []);
215
- let suffix = '';
216
- if (timeframe !== undefined) {
217
- suffix = ':' + timeframe;
218
- }
219
- for (let i = 0; i < marketsWithCurrentId.length; i++) {
220
- market = marketsWithCurrentId[i];
221
- const symbol = market['symbol'];
222
- const messageHash = hash + symbol + suffix;
223
- if (this.inArray(messageHash, messageHashes)) {
224
- return market;
225
- }
226
- }
227
- return market;
228
- }
229
- /**
230
- * @method
231
- * @name coincatch#watchTicker
232
- * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
233
- * @see https://coincatch.github.io/github.io/en/spot/#tickers-channel
234
- * @param {string} symbol unified symbol of the market to fetch the ticker for
235
- * @param {object} [params] extra parameters specific to the exchange API endpoint
236
- * @param {string} [params.instType] the type of the instrument to fetch the ticker for, 'SP' for spot markets, 'MC' for futures markets (default is 'SP')
237
- * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
238
- */
239
- async watchTicker(symbol, params = {}) {
240
- await this.loadMarkets();
241
- const market = this.market(symbol);
242
- const [instType, instId] = this.getPublicInstTypeAndId(market);
243
- const channel = 'ticker';
244
- const messageHash = channel + ':' + symbol;
245
- const args = {
246
- 'instType': instType,
247
- 'channel': channel,
248
- 'instId': instId,
249
- };
250
- return await this.watchPublic(messageHash, messageHash, args, params);
251
- }
252
- /**
253
- * @method
254
- * @name coincatch#unWatchTicker
255
- * @description unsubscribe from the ticker channel
256
- * @see https://coincatch.github.io/github.io/en/mix/#tickers-channel
257
- * @param {string} symbol unified symbol of the market to unwatch the ticker for
258
- * @param {object} [params] extra parameters specific to the exchange API endpoint
259
- * @returns {any} status of the unwatch request
260
- */
261
- async unWatchTicker(symbol, params = {}) {
262
- await this.loadMarkets();
263
- return await this.unWatchChannel(symbol, 'ticker', 'ticker', params);
264
- }
265
- /**
266
- * @method
267
- * @name coincatch#watchTickers
268
- * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
269
- * @see https://coincatch.github.io/github.io/en/mix/#tickers-channel
270
- * @param {string[]} symbols unified symbol of the market to watch the tickers for
271
- * @param {object} [params] extra parameters specific to the exchange API endpoint
272
- * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
273
- */
274
- async watchTickers(symbols = undefined, params = {}) {
275
- await this.loadMarkets();
276
- if (symbols === undefined) {
277
- symbols = this.symbols;
278
- }
279
- const topics = [];
280
- const messageHashes = [];
281
- for (let i = 0; i < symbols.length; i++) {
282
- const symbol = symbols[i];
283
- const market = this.market(symbol);
284
- const [instType, instId] = this.getPublicInstTypeAndId(market);
285
- const args = {
286
- 'instType': instType,
287
- 'channel': 'ticker',
288
- 'instId': instId,
289
- };
290
- topics.push(args);
291
- messageHashes.push('ticker:' + symbol);
292
- }
293
- const tickers = await this.watchPublicMultiple(messageHashes, messageHashes, topics, params);
294
- if (this.newUpdates) {
295
- const result = {};
296
- result[tickers['symbol']] = tickers;
297
- return result;
298
- }
299
- return this.filterByArray(this.tickers, 'symbol', symbols);
300
- }
301
- handleTicker(client, message) {
302
- //
303
- // action: 'snapshot',
304
- // arg: { instType: 'sp', channel: 'ticker', instId: 'ETHUSDT' },
305
- // data: [
306
- // {
307
- // instId: 'ETHUSDT',
308
- // last: '2421.06',
309
- // open24h: '2416.93',
310
- // high24h: '2441.47',
311
- // low24h: '2352.99',
312
- // bestBid: '2421.03',
313
- // bestAsk: '2421.06',
314
- // baseVolume: '9445.2043',
315
- // quoteVolume: '22807159.1148',
316
- // ts: 1728131730687,
317
- // labeId: 0,
318
- // openUtc: '2414.50',
319
- // chgUTC: '0.00272',
320
- // bidSz: '3.866',
321
- // askSz: '0.124'
322
- // }
323
- // ],
324
- // ts: 1728131730688
325
- //
326
- const arg = this.safeDict(message, 'arg', {});
327
- let market = this.getMarketFromArg(arg);
328
- const marketId = market['id'];
329
- const hash = 'ticker:';
330
- if (marketId.indexOf('_DMCBL') >= 0) {
331
- market = this.handleDMCBLMarketByMessageHashes(market, hash, client);
332
- }
333
- const data = this.safeList(message, 'data', []);
334
- const ticker = this.parseWsTicker(this.safeDict(data, 0, {}), market);
335
- const symbol = market['symbol'];
336
- this.tickers[symbol] = ticker;
337
- const messageHash = hash + symbol;
338
- client.resolve(this.tickers[symbol], messageHash);
339
- }
340
- parseWsTicker(ticker, market = undefined) {
341
- //
342
- // spot
343
- // {
344
- // instId: 'ETHUSDT',
345
- // last: '2421.06',
346
- // open24h: '2416.93',
347
- // high24h: '2441.47',
348
- // low24h: '2352.99',
349
- // bestBid: '2421.03',
350
- // bestAsk: '2421.06',
351
- // baseVolume: '9445.2043',
352
- // quoteVolume: '22807159.1148',
353
- // ts: 1728131730687,
354
- // labeId: 0,
355
- // openUtc: '2414.50',
356
- // chgUTC: '0.00272',
357
- // bidSz: '3.866',
358
- // askSz: '0.124'
359
- // }
360
- //
361
- // swap
362
- // {
363
- // instId: 'ETHUSDT',
364
- // last: '2434.47',
365
- // bestAsk: '2434.48',
366
- // bestBid: '2434.47',
367
- // high24h: '2471.68',
368
- // low24h: '2400.01',
369
- // priceChangePercent: '0.00674',
370
- // capitalRate: '0.000082',
371
- // nextSettleTime: 1728489600000,
372
- // systemTime: 1728471993602,
373
- // markPrice: '2434.46',
374
- // indexPrice: '2435.44',
375
- // holding: '171450.25',
376
- // baseVolume: '1699298.91',
377
- // quoteVolume: '4144522832.32',
378
- // openUtc: '2439.67',
379
- // chgUTC: '-0.00213',
380
- // symbolType: 1,
381
- // symbolId: 'ETHUSDT_UMCBL',
382
- // deliveryPrice: '0',
383
- // bidSz: '26.12',
384
- // askSz: '49.6'
385
- // }
386
- //
387
- const last = this.safeString(ticker, 'last');
388
- const timestamp = this.safeInteger2(ticker, 'ts', 'systemTime');
389
- return this.safeTicker({
390
- 'symbol': market['symbol'],
391
- 'timestamp': timestamp,
392
- 'datetime': this.iso8601(timestamp),
393
- 'high': this.safeString(ticker, 'high24h'),
394
- 'low': this.safeString(ticker, 'low24h'),
395
- 'bid': this.safeString(ticker, 'bestBid'),
396
- 'bidVolume': this.safeString(ticker, 'bidSz'),
397
- 'ask': this.safeString(ticker, 'bestAsk'),
398
- 'askVolume': this.safeString(ticker, 'askSz'),
399
- 'vwap': undefined,
400
- 'open': this.safeString2(ticker, 'open24h', 'openUtc'),
401
- 'close': last,
402
- 'last': last,
403
- 'previousClose': undefined,
404
- 'change': undefined,
405
- 'percentage': Precise["default"].stringMul(this.safeString(ticker, 'chgUTC'), '100'),
406
- 'average': undefined,
407
- 'baseVolume': this.safeNumber(ticker, 'baseVolume'),
408
- 'quoteVolume': this.safeNumber(ticker, 'quoteVolume'),
409
- 'indexPrice': this.safeString(ticker, 'indexPrice'),
410
- 'markPrice': this.safeString(ticker, 'markPrice'),
411
- 'info': ticker,
412
- }, market);
413
- }
414
- /**
415
- * @method
416
- * @name coincatch#watchOHLCV
417
- * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
418
- * @see https://coincatch.github.io/github.io/en/spot/#candlesticks-channel
419
- * @param {string} symbol unified symbol of the market to fetch OHLCV data for
420
- * @param {string} timeframe the length of time each candle represents
421
- * @param {int} [since] timestamp in ms of the earliest candle to fetch (not including)
422
- * @param {int} [limit] the maximum amount of candles to fetch (not including)
423
- * @param {object} [params] extra parameters specific to the exchange API endpoint
424
- * @param {bool} [params.instType] the type of the instrument to fetch the OHLCV data for, 'SP' for spot markets, 'MC' for futures markets (default is 'SP')
425
- * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
426
- */
427
- async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
428
- await this.loadMarkets();
429
- const market = this.market(symbol);
430
- const timeframes = this.options['timeframesForWs'];
431
- const channel = 'candle' + this.safeString(timeframes, timeframe);
432
- const [instType, instId] = this.getPublicInstTypeAndId(market);
433
- const args = {
434
- 'instType': instType,
435
- 'channel': channel,
436
- 'instId': instId,
437
- };
438
- const messageHash = 'ohlcv:' + symbol + ':' + timeframe;
439
- const ohlcv = await this.watchPublic(messageHash, messageHash, args, params);
440
- if (this.newUpdates) {
441
- limit = ohlcv.getLimit(symbol, limit);
442
- }
443
- return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
444
- }
445
- /**
446
- * @method
447
- * @name coincatch#unWatchOHLCV
448
- * @description unsubscribe from the ohlcv channel
449
- * @see https://www.bitget.com/api-doc/spot/websocket/public/Candlesticks-Channel
450
- * @param {string} symbol unified symbol of the market to unwatch the ohlcv for
451
- * @param timeframe
452
- * @param {object} [params] extra parameters specific to the exchange API endpoint
453
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
454
- */
455
- async unWatchOHLCV(symbol, timeframe = '1m', params = {}) {
456
- await this.loadMarkets();
457
- const timeframes = this.options['timeframesForWs'];
458
- const interval = this.safeString(timeframes, timeframe);
459
- const channel = 'candle' + interval;
460
- return await this.unWatchChannel(symbol, channel, 'ohlcv:' + interval, params);
461
- }
462
- handleOHLCV(client, message) {
463
- //
464
- // {
465
- // action: 'update',
466
- // arg: { instType: 'sp', channel: 'candle1D', instId: 'ETHUSDT' },
467
- // data: [
468
- // [
469
- // '1728316800000',
470
- // '2474.5',
471
- // '2478.21',
472
- // '2459.8',
473
- // '2463.51',
474
- // '86.0551'
475
- // ]
476
- // ],
477
- // ts: 1728317607657
478
- // }
479
- //
480
- const arg = this.safeDict(message, 'arg', {});
481
- let market = this.getMarketFromArg(arg);
482
- const marketId = market['id'];
483
- const hash = 'ohlcv:';
484
- const data = this.safeList(message, 'data', []);
485
- const channel = this.safeString(arg, 'channel');
486
- const klineType = channel.slice(6);
487
- const timeframe = this.findTimeframe(klineType);
488
- if (marketId.indexOf('_DMCBL') >= 0) {
489
- market = this.handleDMCBLMarketByMessageHashes(market, hash, client, timeframe);
490
- }
491
- const symbol = market['symbol'];
492
- if (!(symbol in this.ohlcvs)) {
493
- this.ohlcvs[symbol] = {};
494
- }
495
- if (!(timeframe in this.ohlcvs[symbol])) {
496
- const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
497
- this.ohlcvs[symbol][timeframe] = new Cache.ArrayCacheByTimestamp(limit);
498
- }
499
- const stored = this.ohlcvs[symbol][timeframe];
500
- for (let i = 0; i < data.length; i++) {
501
- const candle = this.safeList(data, i, []);
502
- const parsed = this.parseWsOHLCV(candle, market);
503
- stored.append(parsed);
504
- }
505
- const messageHash = hash + symbol + ':' + timeframe;
506
- client.resolve(stored, messageHash);
507
- }
508
- parseWsOHLCV(ohlcv, market = undefined) {
509
- //
510
- // [
511
- // '1728316800000',
512
- // '2474.5',
513
- // '2478.21',
514
- // '2459.8',
515
- // '2463.51',
516
- // '86.0551'
517
- // ]
518
- //
519
- return [
520
- this.safeInteger(ohlcv, 0),
521
- this.safeNumber(ohlcv, 1),
522
- this.safeNumber(ohlcv, 2),
523
- this.safeNumber(ohlcv, 3),
524
- this.safeNumber(ohlcv, 4),
525
- this.safeNumber(ohlcv, 5),
526
- ];
527
- }
528
- /**
529
- * @method
530
- * @name coincatch#watchOrderBook
531
- * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
532
- * @see https://coincatch.github.io/github.io/en/spot/#depth-channel
533
- * @param {string} symbol unified symbol of the market to fetch the order book for
534
- * @param {int} [limit] the maximum amount of order book entries to return
535
- * @param {object} [params] extra parameters specific to the exchange API endpoint
536
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
537
- */
538
- async watchOrderBook(symbol, limit = undefined, params = {}) {
539
- return await this.watchOrderBookForSymbols([symbol], limit, params);
540
- }
541
- /**
542
- * @method
543
- * @name coincatch#unWatchOrderBook
544
- * @description unsubscribe from the orderbook channel
545
- * @see https://coincatch.github.io/github.io/en/spot/#depth-channel
546
- * @param {string} symbol unified symbol of the market to fetch the order book for
547
- * @param {object} [params] extra parameters specific to the exchange API endpoint
548
- * @param {int} [params.limit] orderbook limit, default is undefined
549
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
550
- */
551
- async unWatchOrderBook(symbol, params = {}) {
552
- await this.loadMarkets();
553
- let channel = 'books';
554
- const limit = this.safeInteger(params, 'limit');
555
- if ((limit === 5) || (limit === 15)) {
556
- params = this.omit(params, 'limit');
557
- channel += limit.toString();
558
- }
559
- return await this.unWatchChannel(symbol, channel, channel, params);
560
- }
561
- /**
562
- * @method
563
- * @name coincatch#watchOrderBookForSymbols
564
- * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
565
- * @see https://coincatch.github.io/github.io/en/spot/#depth-channel
566
- * @param symbols
567
- * @param {int} [limit] the maximum amount of order book entries to return
568
- * @param {object} [params] extra parameters specific to the exchange API endpoint
569
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
570
- */
571
- async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
572
- await this.loadMarkets();
573
- symbols = this.marketSymbols(symbols);
574
- const channel = 'books';
575
- const topics = [];
576
- const messageHashes = [];
577
- for (let i = 0; i < symbols.length; i++) {
578
- const symbol = symbols[i];
579
- const market = this.market(symbol);
580
- const [instType, instId] = this.getPublicInstTypeAndId(market);
581
- const args = {
582
- 'instType': instType,
583
- 'channel': channel,
584
- 'instId': instId,
585
- };
586
- topics.push(args);
587
- messageHashes.push(channel + ':' + symbol);
588
- }
589
- const orderbook = await this.watchPublicMultiple(messageHashes, messageHashes, topics, params);
590
- return orderbook.limit();
591
- }
592
- handleOrderBook(client, message) {
593
- //
594
- // {
595
- // action: 'update',
596
- // arg: { instType: 'sp', channel: 'books', instId: 'ETHUSDT' },
597
- // data: [
598
- // {
599
- // asks: [ [ 2507.07, 0.4248 ] ],
600
- // bids: [ [ 2507.05, 0.1198 ] ],
601
- // checksum: -1400923312,
602
- // ts: '1728339446908'
603
- // }
604
- // ],
605
- // ts: 1728339446908
606
- // }
607
- //
608
- const arg = this.safeDict(message, 'arg', {});
609
- let market = this.getMarketFromArg(arg);
610
- const marketId = market['id'];
611
- const hash = 'books:';
612
- if (marketId.indexOf('_DMCBL') >= 0) {
613
- market = this.handleDMCBLMarketByMessageHashes(market, hash, client);
614
- }
615
- const symbol = market['symbol'];
616
- const channel = this.safeString(arg, 'channel');
617
- const messageHash = hash + symbol;
618
- const data = this.safeList(message, 'data', []);
619
- const rawOrderBook = this.safeDict(data, 0);
620
- const timestamp = this.safeInteger(rawOrderBook, 'ts');
621
- const incrementalBook = channel;
622
- if (incrementalBook) {
623
- if (!(symbol in this.orderbooks)) {
624
- const ob = this.countedOrderBook({});
625
- ob['symbol'] = symbol;
626
- this.orderbooks[symbol] = ob;
627
- }
628
- const storedOrderBook = this.orderbooks[symbol];
629
- const asks = this.safeList(rawOrderBook, 'asks', []);
630
- const bids = this.safeList(rawOrderBook, 'bids', []);
631
- this.handleDeltas(storedOrderBook['asks'], asks);
632
- this.handleDeltas(storedOrderBook['bids'], bids);
633
- storedOrderBook['timestamp'] = timestamp;
634
- storedOrderBook['datetime'] = this.iso8601(timestamp);
635
- const checksum = this.safeBool(this.options, 'checksum', true);
636
- const isSnapshot = this.safeString(message, 'action') === 'snapshot';
637
- if (!isSnapshot && checksum) {
638
- const storedAsks = storedOrderBook['asks'];
639
- const storedBids = storedOrderBook['bids'];
640
- const asksLength = storedAsks.length;
641
- const bidsLength = storedBids.length;
642
- const payloadArray = [];
643
- for (let i = 0; i < 25; i++) {
644
- if (i < bidsLength) {
645
- payloadArray.push(storedBids[i][2][0]);
646
- payloadArray.push(storedBids[i][2][1]);
647
- }
648
- if (i < asksLength) {
649
- payloadArray.push(storedAsks[i][2][0]);
650
- payloadArray.push(storedAsks[i][2][1]);
651
- }
652
- }
653
- const payload = payloadArray.join(':');
654
- const calculatedChecksum = this.crc32(payload, true);
655
- const responseChecksum = this.safeInteger(rawOrderBook, 'checksum');
656
- if (calculatedChecksum !== responseChecksum) {
657
- this.spawn(this.handleCheckSumError, client, symbol, messageHash);
658
- return;
659
- }
660
- }
661
- }
662
- else {
663
- const orderbook = this.orderBook({});
664
- const parsedOrderbook = this.parseOrderBook(rawOrderBook, symbol, timestamp);
665
- orderbook.reset(parsedOrderbook);
666
- this.orderbooks[symbol] = orderbook;
667
- }
668
- client.resolve(this.orderbooks[symbol], messageHash);
669
- }
670
- async handleCheckSumError(client, symbol, messageHash) {
671
- await this.unWatchOrderBook(symbol);
672
- const error = new errors.ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
673
- client.reject(error, messageHash);
674
- }
675
- handleDelta(bookside, delta) {
676
- const bidAsk = this.parseBidAsk(delta, 0, 1);
677
- bidAsk.push(delta);
678
- bookside.storeArray(bidAsk);
679
- }
680
- handleDeltas(bookside, deltas) {
681
- for (let i = 0; i < deltas.length; i++) {
682
- this.handleDelta(bookside, deltas[i]);
683
- }
684
- }
685
- /**
686
- * @method
687
- * @name coincatch#watchTrades
688
- * @description get the list of most recent trades for a particular symbol
689
- * @see https://coincatch.github.io/github.io/en/spot/#trades-channel
690
- * @param {string} symbol unified symbol of the market to fetch trades for
691
- * @param {int} [since] timestamp in ms of the earliest trade to fetch
692
- * @param {int} [limit] the maximum amount of trades to fetch
693
- * @param {object} [params] extra parameters specific to the exchange API endpoint
694
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
695
- */
696
- async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
697
- return await this.watchTradesForSymbols([symbol], since, limit, params);
698
- }
699
- /**
700
- * @method
701
- * @name coincatch#watchTradesForSymbols
702
- * @description watches information on multiple trades made in a market
703
- * @see https://coincatch.github.io/github.io/en/spot/#trades-channel
704
- * @param symbols
705
- * @param {int} [since] the earliest time in ms to fetch orders for
706
- * @param {int} [limit] the maximum number of trade structures to retrieve
707
- * @param {object} [params] extra parameters specific to the exchange API endpoint
708
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure}
709
- */
710
- async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
711
- const symbolsLength = symbols.length;
712
- if (symbolsLength === 0) {
713
- throw new errors.ArgumentsRequired(this.id + ' watchTradesForSymbols() requires a non-empty array of symbols');
714
- }
715
- await this.loadMarkets();
716
- symbols = this.marketSymbols(symbols);
717
- const topics = [];
718
- const messageHashes = [];
719
- for (let i = 0; i < symbols.length; i++) {
720
- const symbol = symbols[i];
721
- const market = this.market(symbol);
722
- const [instType, instId] = this.getPublicInstTypeAndId(market);
723
- const args = {
724
- 'instType': instType,
725
- 'channel': 'trade',
726
- 'instId': instId,
727
- };
728
- topics.push(args);
729
- messageHashes.push('trade:' + symbol);
730
- }
731
- const trades = await this.watchPublicMultiple(messageHashes, messageHashes, topics, params);
732
- if (this.newUpdates) {
733
- const first = this.safeDict(trades, 0);
734
- const tradeSymbol = this.safeString(first, 'symbol');
735
- limit = trades.getLimit(tradeSymbol, limit);
736
- }
737
- return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
738
- }
739
- /**
740
- * @method
741
- * @name coincatch#unWatchTrades
742
- * @description unsubscribe from the trades channel
743
- * @see https://coincatch.github.io/github.io/en/spot/#trades-channel
744
- * @param {string} symbol unified symbol of the market to unwatch the trades for
745
- * @param {object} [params] extra parameters specific to the exchange API endpoint
746
- * @returns {any} status of the unwatch request
747
- */
748
- async unWatchTrades(symbol, params = {}) {
749
- await this.loadMarkets();
750
- return await this.unWatchChannel(symbol, 'trade', 'trade', params);
751
- }
752
- handleTrades(client, message) {
753
- //
754
- // {
755
- // action: 'update',
756
- // arg: { instType: 'sp', channel: 'trade', instId: 'ETHUSDT' },
757
- // data: [ [ '1728341807469', '2421.41', '0.478', 'sell' ] ],
758
- // ts: 1728341807482
759
- // }
760
- //
761
- const arg = this.safeDict(message, 'arg', {});
762
- let market = this.getMarketFromArg(arg);
763
- const marketId = market['id'];
764
- const hash = 'trade:';
765
- if (marketId.indexOf('_DMCBL') >= 0) {
766
- market = this.handleDMCBLMarketByMessageHashes(market, hash, client);
767
- }
768
- const symbol = market['symbol'];
769
- if (!(symbol in this.trades)) {
770
- const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
771
- this.trades[symbol] = new Cache.ArrayCache(limit);
772
- }
773
- const stored = this.trades[symbol];
774
- let data = this.safeList(message, 'data', []);
775
- if (data !== undefined) {
776
- data = this.sortBy(data, 0);
777
- for (let i = 0; i < data.length; i++) {
778
- const trade = this.safeList(data, i);
779
- const parsed = this.parseWsTrade(trade, market);
780
- stored.append(parsed);
781
- }
782
- }
783
- const messageHash = hash + symbol;
784
- client.resolve(stored, messageHash);
785
- }
786
- parseWsTrade(trade, market = undefined) {
787
- //
788
- // [
789
- // '1728341807469',
790
- // '2421.41',
791
- // '0.478',
792
- // 'sell'
793
- // ]
794
- //
795
- const timestamp = this.safeInteger(trade, 0);
796
- return this.safeTrade({
797
- 'id': undefined,
798
- 'timestamp': timestamp,
799
- 'datetime': this.iso8601(timestamp),
800
- 'symbol': market['symbol'],
801
- 'side': this.safeStringLower(trade, 3),
802
- 'price': this.safeString(trade, 1),
803
- 'amount': this.safeString(trade, 2),
804
- 'cost': undefined,
805
- 'takerOrMaker': undefined,
806
- 'type': undefined,
807
- 'order': undefined,
808
- 'fee': undefined,
809
- 'info': trade,
810
- }, market);
811
- }
812
- /**
813
- * @method
814
- * @name coincatch#watchBalance
815
- * @description watch balance and get the amount of funds available for trading or funds locked in orders
816
- * @see https://coincatch.github.io/github.io/en/spot/#account-channel
817
- * @see https://coincatch.github.io/github.io/en/mix/#account-channel
818
- * @param {object} [params] extra parameters specific to the exchange API endpoint
819
- * @param {str} [params.type] 'spot' or 'swap' (default is 'spot')
820
- * @param {string} [params.instType] *swap only* 'umcbl' or 'dmcbl' (default is 'umcbl')
821
- * @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
822
- */
823
- async watchBalance(params = {}) {
824
- let type = undefined;
825
- [type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
826
- let instType = 'spbl'; // must be lower case for spot
827
- if (type === 'swap') {
828
- instType = 'umcbl';
829
- }
830
- const channel = 'account';
831
- [instType, params] = this.handleOptionAndParams(params, 'watchBalance', 'instType', instType);
832
- const args = {
833
- 'instType': instType,
834
- 'channel': channel,
835
- 'instId': 'default',
836
- };
837
- const messageHash = 'balance:' + instType.toLowerCase();
838
- return await this.watchPrivate(messageHash, messageHash, args, params);
839
- }
840
- handleBalance(client, message) {
841
- //
842
- // spot
843
- // {
844
- // action: 'snapshot',
845
- // arg: { instType: 'spbl', channel: 'account', instId: 'default' },
846
- // data: [
847
- // {
848
- // coinId: '3',
849
- // coinName: 'ETH',
850
- // available: '0.0000832',
851
- // frozen: '0',
852
- // lock: '0'
853
- // }
854
- // ],
855
- // ts: 1728464548725
856
- // }
857
- //
858
- // // swap
859
- // {
860
- // action: 'snapshot',
861
- // arg: { instType: 'dmcbl', channel: 'account', instId: 'default' },
862
- // data: [
863
- // {
864
- // marginCoin: 'ETH',
865
- // locked: '0.00000000',
866
- // available: '0.00001203',
867
- // maxOpenPosAvailable: '0.00001203',
868
- // maxTransferOut: '0.00001203',
869
- // equity: '0.00001203',
870
- // usdtEquity: '0.029092328738',
871
- // coinDisplayName: 'ETH'
872
- // }
873
- // ],
874
- // ts: 1728650777643
875
- // }
876
- //
877
- const data = this.safeList(message, 'data', []);
878
- for (let i = 0; i < data.length; i++) {
879
- const rawBalance = data[i];
880
- const currencyId = this.safeString2(rawBalance, 'coinName', 'marginCoin');
881
- const code = this.safeCurrencyCode(currencyId);
882
- const account = (code in this.balance) ? this.balance[code] : this.account();
883
- const freeQuery = ('maxTransferOut' in rawBalance) ? 'maxTransferOut' : 'available';
884
- account['free'] = this.safeString(rawBalance, freeQuery);
885
- account['total'] = this.safeString(rawBalance, 'equity');
886
- account['used'] = this.safeString(rawBalance, 'frozen');
887
- this.balance[code] = account;
888
- }
889
- this.balance = this.safeBalance(this.balance);
890
- const arg = this.safeDict(message, 'arg');
891
- const instType = this.safeStringLower(arg, 'instType');
892
- const messageHash = 'balance:' + instType;
893
- client.resolve(this.balance, messageHash);
894
- }
895
- /**
896
- * @method
897
- * @name coincatch#watchOrders
898
- * @description watches information on multiple orders made by the user
899
- * @see https://coincatch.github.io/github.io/en/spot/#order-channel
900
- * @see https://coincatch.github.io/github.io/en/mix/#order-channel
901
- * @see https://coincatch.github.io/github.io/en/mix/#plan-order-channel
902
- * @param {string} symbol unified market symbol of the market orders were made in
903
- * @param {int} [since] the earliest time in ms to fetch orders for
904
- * @param {int} [limit] the maximum number of order structures to retrieve
905
- * @param {object} [params] extra parameters specific to the exchange API endpoint
906
- * @param {string} [params.type] 'spot' or 'swap'
907
- * @param {string} [params.instType] *swap only* 'umcbl' or 'dmcbl' (default is 'umcbl')
908
- * @param {bool} [params.trigger] *swap only* whether to watch trigger orders (default is false)
909
- * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
910
- */
911
- async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
912
- const methodName = 'watchOrders';
913
- await this.loadMarkets();
914
- let market = undefined;
915
- let marketId = undefined;
916
- if (symbol !== undefined) {
917
- market = this.market(symbol);
918
- symbol = market['symbol'];
919
- marketId = market['id'];
920
- }
921
- let marketType = undefined;
922
- [marketType, params] = this.handleMarketTypeAndParams(methodName, market, params);
923
- let instType = 'spbl';
924
- let instId = marketId;
925
- if (marketType === 'spot') {
926
- if (symbol === undefined) {
927
- throw new errors.ArgumentsRequired(this.id + ' ' + methodName + '() requires a symbol argument for ' + marketType + ' markets.');
928
- }
929
- }
930
- else {
931
- instId = 'default';
932
- instType = 'umcbl';
933
- if (symbol === undefined) {
934
- [instType, params] = this.handleOptionAndParams(params, methodName, 'instType', instType);
935
- }
936
- else {
937
- if (marketId.indexOf('_DMCBL') >= 0) {
938
- instType = 'dmcbl';
939
- }
940
- }
941
- }
942
- let channel = 'orders';
943
- const isTrigger = this.safeBool(params, 'trigger');
944
- if (isTrigger) {
945
- channel = 'ordersAlgo'; // channel does not return any data
946
- params = this.omit(params, 'trigger');
947
- }
948
- const args = {
949
- 'instType': instType,
950
- 'channel': channel,
951
- 'instId': instId,
952
- };
953
- let messageHash = 'orders';
954
- if (symbol !== undefined) {
955
- messageHash += ':' + symbol;
956
- }
957
- const orders = await this.watchPrivate(messageHash, messageHash, args, params);
958
- if (this.newUpdates) {
959
- limit = orders.getLimit(symbol, limit);
960
- }
961
- return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
962
- }
963
- handleOrder(client, message) {
964
- //
965
- // spot
966
- //
967
- // {
968
- // action: 'snapshot',
969
- // arg: { instType: 'spbl', channel: 'orders', instId: 'ETHUSDT_SPBL' },
970
- // data: [
971
- // {
972
- // instId: 'ETHUSDT_SPBL',
973
- // ordId: '1228627925964996608',
974
- // clOrdId: 'f0cccf74-c535-4523-a53d-dbe3b9958559',
975
- // px: '2000',
976
- // sz: '0.001',
977
- // notional: '2',
978
- // ordType: 'limit',
979
- // force: 'normal',
980
- // side: 'buy',
981
- // accFillSz: '0',
982
- // avgPx: '0',
983
- // status: 'new',
984
- // cTime: 1728653645030,
985
- // uTime: 1728653645030,
986
- // orderFee: [],
987
- // eps: 'API'
988
- // }
989
- // ],
990
- // ts: 1728653645046
991
- // }
992
- //
993
- // swap
994
- //
995
- // {
996
- // action: 'snapshot',
997
- // arg: { instType: 'umcbl', channel: 'orders', instId: 'default' },
998
- // data: [
999
- // {
1000
- // accFillSz: '0',
1001
- // cTime: 1728653796976,
1002
- // clOrdId: '1228628563272753152',
1003
- // eps: 'API',
1004
- // force: 'normal',
1005
- // hM: 'single_hold',
1006
- // instId: 'ETHUSDT_UMCBL',
1007
- // lever: '5',
1008
- // low: false,
1009
- // notionalUsd: '20',
1010
- // ordId: '1228628563188867072',
1011
- // ordType: 'limit',
1012
- // orderFee: [],
1013
- // posSide: 'net',
1014
- // px: '2000',
1015
- // side: 'buy',
1016
- // status: 'new',
1017
- // sz: '0.01',
1018
- // tS: 'buy_single',
1019
- // tdMode: 'cross',
1020
- // tgtCcy: 'USDT',
1021
- // uTime: 1728653796976
1022
- // }
1023
- // ],
1024
- // ts: 1728653797002
1025
- // }
1026
- //
1027
- //
1028
- const arg = this.safeDict(message, 'arg', {});
1029
- const instType = this.safeString(arg, 'instType');
1030
- const argInstId = this.safeString(arg, 'instId');
1031
- let marketType = undefined;
1032
- if (instType === 'spbl') {
1033
- marketType = 'spot';
1034
- }
1035
- else {
1036
- marketType = 'swap';
1037
- }
1038
- const data = this.safeList(message, 'data', []);
1039
- if (this.orders === undefined) {
1040
- const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
1041
- this.orders = new Cache.ArrayCacheBySymbolById(limit);
1042
- }
1043
- const hash = 'orders';
1044
- const stored = this.orders;
1045
- let symbol = undefined;
1046
- for (let i = 0; i < data.length; i++) {
1047
- const order = data[i];
1048
- const marketId = this.safeString(order, 'instId', argInstId);
1049
- const market = this.safeMarket(marketId, undefined, undefined, marketType);
1050
- const parsed = this.parseWsOrder(order, market);
1051
- stored.append(parsed);
1052
- symbol = parsed['symbol'];
1053
- const messageHash = 'orders:' + symbol;
1054
- client.resolve(stored, messageHash);
1055
- }
1056
- client.resolve(stored, hash);
1057
- }
1058
- parseWsOrder(order, market = undefined) {
1059
- //
1060
- // spot
1061
- // {
1062
- // instId: 'ETHUSDT_SPBL',
1063
- // ordId: '1228627925964996608',
1064
- // clOrdId: 'f0cccf74-c535-4523-a53d-dbe3b9958559',
1065
- // px: '2000',
1066
- // sz: '0.001',
1067
- // notional: '2',
1068
- // ordType: 'limit',
1069
- // force: 'normal',
1070
- // side: 'buy',
1071
- // accFillSz: '0',
1072
- // avgPx: '0',
1073
- // status: 'new',
1074
- // cTime: 1728653645030,
1075
- // uTime: 1728653645030,
1076
- // orderFee: orderFee: [ { fee: '0', feeCcy: 'USDT' } ],
1077
- // eps: 'API'
1078
- // }
1079
- //
1080
- // swap
1081
- // {
1082
- // accFillSz: '0',
1083
- // cTime: 1728653796976,
1084
- // clOrdId: '1228628563272753152',
1085
- // eps: 'API',
1086
- // force: 'normal',
1087
- // hM: 'single_hold',
1088
- // instId: 'ETHUSDT_UMCBL',
1089
- // lever: '5',
1090
- // low: false,
1091
- // notionalUsd: '20',
1092
- // ordId: '1228628563188867072',
1093
- // ordType: 'limit',
1094
- // orderFee: [ { fee: '0', feeCcy: 'USDT' } ],
1095
- // posSide: 'net',
1096
- // px: '2000',
1097
- // side: 'buy',
1098
- // status: 'new',
1099
- // sz: '0.01',
1100
- // tS: 'buy_single',
1101
- // tdMode: 'cross',
1102
- // tgtCcy: 'USDT',
1103
- // uTime: 1728653796976
1104
- // }
1105
- //
1106
- const marketId = this.safeString(order, 'instId');
1107
- const settleId = this.safeString(order, 'tgtCcy');
1108
- market = this.safeMarketCustom(marketId, market, settleId);
1109
- const timestamp = this.safeInteger(order, 'cTime');
1110
- const symbol = market['symbol'];
1111
- const rawStatus = this.safeString(order, 'status');
1112
- const orderFee = this.safeList(order, 'orderFee', []);
1113
- const fee = this.safeDict(orderFee, 0);
1114
- const feeCost = Precise["default"].stringMul(this.safeString(fee, 'fee'), '-1');
1115
- const feeCurrency = this.safeString(fee, 'feeCcy');
1116
- let price = this.omitZero(this.safeString(order, 'px'));
1117
- const priceAvg = this.omitZero(this.safeString(order, 'avgPx'));
1118
- if (price === undefined) {
1119
- price = priceAvg;
1120
- }
1121
- const type = this.safeStringLower(order, 'ordType');
1122
- return this.safeOrder({
1123
- 'id': this.safeString(order, 'ordId'),
1124
- 'clientOrderId': this.safeString(order, 'clOrdId'),
1125
- 'timestamp': timestamp,
1126
- 'datetime': this.iso8601(timestamp),
1127
- 'lastTradeTimestamp': undefined,
1128
- 'lastUpdateTimestamp': this.safeInteger(order, 'uTime'),
1129
- 'status': this.parseOrderStatus(rawStatus),
1130
- 'symbol': symbol,
1131
- 'type': type,
1132
- 'timeInForce': this.parseOrderTimeInForce(this.safeStringLower(order, 'force')),
1133
- 'side': this.safeStringLower(order, 'side'),
1134
- 'price': price,
1135
- 'average': this.safeString(order, 'avgPx'),
1136
- 'amount': this.safeString(order, 'sz'),
1137
- 'filled': this.safeString(order, 'accFillSz'),
1138
- 'remaining': undefined,
1139
- 'triggerPrice': undefined,
1140
- 'takeProfitPrice': undefined,
1141
- 'stopLossPrice': undefined,
1142
- 'cost': this.safeString(order, 'notional'),
1143
- 'trades': undefined,
1144
- 'fee': {
1145
- 'currency': feeCurrency,
1146
- 'cost': feeCost,
1147
- },
1148
- 'reduceOnly': this.safeBool(order, 'low'),
1149
- 'postOnly': undefined,
1150
- 'info': order,
1151
- }, market);
1152
- }
1153
- /**
1154
- * @method
1155
- * @name coincatch#watchPositions
1156
- * @description watch all open positions
1157
- * @see https://coincatch.github.io/github.io/en/mix/#positions-channel
1158
- * @param {string[]|undefined} symbols list of unified market symbols
1159
- * @param since
1160
- * @param limit
1161
- * @param {object} params extra parameters specific to the exchange API endpoint
1162
- * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
1163
- */
1164
- async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
1165
- await this.loadMarkets();
1166
- symbols = this.marketSymbols(symbols, 'swap');
1167
- const messageHashes = [];
1168
- const hash = 'positions';
1169
- let instTypes = [];
1170
- if (symbols !== undefined) {
1171
- for (let i = 0; i < symbols.length; i++) {
1172
- const symbol = symbols[i];
1173
- const market = this.market(symbol);
1174
- const instType = this.getPrivateInstType(market);
1175
- if (!this.inArray(instType, instTypes)) {
1176
- instTypes.push(instType);
1177
- }
1178
- messageHashes.push(hash + '::' + symbol);
1179
- }
1180
- }
1181
- else {
1182
- instTypes = ['umcbl', 'dmcbl'];
1183
- messageHashes.push(hash);
1184
- }
1185
- const args = [];
1186
- const subscribeHashes = [];
1187
- for (let i = 0; i < instTypes.length; i++) {
1188
- const instType = instTypes[i];
1189
- const arg = {
1190
- 'instType': instType,
1191
- 'channel': hash,
1192
- 'instId': 'default',
1193
- };
1194
- subscribeHashes.push(hash + '::' + instType);
1195
- args.push(arg);
1196
- }
1197
- const newPositions = await this.watchPrivateMultiple(messageHashes, subscribeHashes, args, params);
1198
- if (this.newUpdates) {
1199
- return newPositions;
1200
- }
1201
- return this.filterBySymbolsSinceLimit(newPositions, symbols, since, limit, true);
1202
- }
1203
- getPrivateInstType(market) {
1204
- const marketId = market['id'];
1205
- if (marketId.indexOf('_DMCBL') >= 0) {
1206
- return 'dmcbl';
1207
- }
1208
- return 'umcbl';
1209
- }
1210
- handlePositions(client, message) {
1211
- //
1212
- // {
1213
- // action: 'snapshot',
1214
- // arg: { instType: 'umcbl', channel: 'positions', instId: 'default' },
1215
- // data: [
1216
- // {
1217
- // posId: '1221355728745619456',
1218
- // instId: 'ETHUSDT_UMCBL',
1219
- // instName: 'ETHUSDT',
1220
- // marginCoin: 'USDT',
1221
- // margin: '5.27182',
1222
- // marginMode: 'crossed',
1223
- // holdSide: 'long',
1224
- // holdMode: 'single_hold',
1225
- // total: '0.01',
1226
- // available: '0.01',
1227
- // locked: '0',
1228
- // averageOpenPrice: '2635.91',
1229
- // leverage: 5,
1230
- // achievedProfits: '0',
1231
- // upl: '-0.0267',
1232
- // uplRate: '-0.005064664576',
1233
- // liqPx: '-3110.66866033',
1234
- // keepMarginRate: '0.0033',
1235
- // marginRate: '0.002460827254',
1236
- // cTime: '1726919818102',
1237
- // uTime: '1728919604312',
1238
- // markPrice: '2633.24',
1239
- // autoMargin: 'off'
1240
- // }
1241
- // ],
1242
- // ts: 1728919604329
1243
- // }
1244
- //
1245
- if (this.positions === undefined) {
1246
- this.positions = new Cache.ArrayCacheBySymbolBySide();
1247
- }
1248
- const cache = this.positions;
1249
- const rawPositions = this.safeValue(message, 'data', []);
1250
- const dataLength = rawPositions.length;
1251
- if (dataLength === 0) {
1252
- return;
1253
- }
1254
- const newPositions = [];
1255
- const symbols = [];
1256
- for (let i = 0; i < rawPositions.length; i++) {
1257
- const rawPosition = rawPositions[i];
1258
- const position = this.parseWsPosition(rawPosition);
1259
- symbols.push(position['symbol']);
1260
- newPositions.push(position);
1261
- cache.append(position);
1262
- }
1263
- const hash = 'positions';
1264
- const messageHashes = this.findMessageHashes(client, hash);
1265
- for (let i = 0; i < messageHashes.length; i++) {
1266
- const messageHash = messageHashes[i];
1267
- const parts = messageHash.split('::');
1268
- const symbol = parts[1];
1269
- if (this.inArray(symbol, symbols)) {
1270
- const positionsForSymbol = [];
1271
- for (let j = 0; j < newPositions.length; j++) {
1272
- const position = newPositions[j];
1273
- if (position['symbol'] === symbol) {
1274
- positionsForSymbol.push(position);
1275
- }
1276
- }
1277
- client.resolve(positionsForSymbol, messageHash);
1278
- }
1279
- }
1280
- client.resolve(newPositions, hash);
1281
- }
1282
- parseWsPosition(position, market = undefined) {
1283
- //
1284
- // {
1285
- // posId: '1221355728745619456',
1286
- // instId: 'ETHUSDT_UMCBL',
1287
- // instName: 'ETHUSDT',
1288
- // marginCoin: 'USDT',
1289
- // margin: '5.27182',
1290
- // marginMode: 'crossed',
1291
- // holdSide: 'long',
1292
- // holdMode: 'single_hold',
1293
- // total: '0.01',
1294
- // available: '0.01',
1295
- // locked: '0',
1296
- // averageOpenPrice: '2635.91',
1297
- // leverage: 5,
1298
- // achievedProfits: '0',
1299
- // upl: '-0.0267',
1300
- // uplRate: '-0.005064664576',
1301
- // liqPx: '-3110.66866033',
1302
- // keepMarginRate: '0.0033',
1303
- // marginRate: '0.002460827254',
1304
- // cTime: '1726919818102',
1305
- // uTime: '1728919604312',
1306
- // markPrice: '2633.24',
1307
- // autoMargin: 'off'
1308
- // }
1309
- //
1310
- const marketId = this.safeString(position, 'symbol');
1311
- const settleId = this.safeString(position, 'marginCoin');
1312
- market = this.safeMarketCustom(marketId, market, settleId);
1313
- const timestamp = this.safeInteger(position, 'cTime');
1314
- const marginModeId = this.safeString(position, 'marginMode');
1315
- const marginMode = this.getSupportedMapping(marginModeId, {
1316
- 'crossed': 'cross',
1317
- 'isolated': 'isolated',
1318
- });
1319
- let isHedged = undefined;
1320
- const holdMode = this.safeString(position, 'holdMode');
1321
- if (holdMode === 'double_hold') {
1322
- isHedged = true;
1323
- }
1324
- else if (holdMode === 'single_hold') {
1325
- isHedged = false;
1326
- }
1327
- const percentageDecimal = this.safeString(position, 'uplRate');
1328
- const percentage = Precise["default"].stringMul(percentageDecimal, '100');
1329
- const margin = this.safeNumber(position, 'margin');
1330
- return this.safePosition({
1331
- 'symbol': market['symbol'],
1332
- 'id': undefined,
1333
- 'timestamp': timestamp,
1334
- 'datetime': this.iso8601(timestamp),
1335
- 'contracts': this.safeNumber(position, 'total'),
1336
- 'contractSize': undefined,
1337
- 'side': this.safeStringLower(position, 'holdSide'),
1338
- 'notional': margin,
1339
- 'leverage': this.safeInteger(position, 'leverage'),
1340
- 'unrealizedPnl': this.safeNumber(position, 'upl'),
1341
- 'realizedPnl': this.safeNumber(position, 'achievedProfits'),
1342
- 'collateral': undefined,
1343
- 'entryPrice': this.safeNumber(position, 'averageOpenPrice'),
1344
- 'markPrice': this.safeNumber(position, 'markPrice'),
1345
- 'liquidationPrice': this.safeNumber(position, 'liqPx'),
1346
- 'marginMode': marginMode,
1347
- 'hedged': isHedged,
1348
- 'maintenanceMargin': undefined,
1349
- 'maintenanceMarginPercentage': this.safeNumber(position, 'keepMarginRate'),
1350
- 'initialMargin': margin,
1351
- 'initialMarginPercentage': undefined,
1352
- 'marginRatio': this.safeNumber(position, 'marginRate'),
1353
- 'lastUpdateTimestamp': this.safeInteger(position, 'uTime'),
1354
- 'lastPrice': undefined,
1355
- 'stopLossPrice': undefined,
1356
- 'takeProfitPrice': undefined,
1357
- 'percentage': percentage,
1358
- 'info': position,
1359
- });
1360
- }
1361
- handleErrorMessage(client, message) {
1362
- //
1363
- // { event: "error", code: 30001, msg: "Channel does not exist" }
1364
- //
1365
- const event = this.safeString(message, 'event');
1366
- try {
1367
- if (event === 'error') {
1368
- const code = this.safeString(message, 'code');
1369
- const feedback = this.id + ' ' + this.json(message);
1370
- this.throwExactlyMatchedException(this.exceptions['ws']['exact'], code, feedback);
1371
- const msg = this.safeString(message, 'msg', '');
1372
- this.throwBroadlyMatchedException(this.exceptions['ws']['broad'], msg, feedback);
1373
- throw new errors.ExchangeError(feedback);
1374
- }
1375
- return false;
1376
- }
1377
- catch (e) {
1378
- if (e instanceof errors.AuthenticationError) {
1379
- const messageHash = 'authenticated';
1380
- client.reject(e, messageHash);
1381
- if (messageHash in client.subscriptions) {
1382
- delete client.subscriptions[messageHash];
1383
- }
1384
- }
1385
- else {
1386
- client.reject(e);
1387
- }
1388
- return true;
1389
- }
1390
- }
1391
- handleMessage(client, message) {
1392
- // todo handle with subscribe and unsubscribe
1393
- if (this.handleErrorMessage(client, message)) {
1394
- return;
1395
- }
1396
- const content = this.safeString(message, 'message');
1397
- if (content === 'pong') {
1398
- this.handlePong(client, message);
1399
- return;
1400
- }
1401
- if (message === 'pong') {
1402
- this.handlePong(client, message);
1403
- return;
1404
- }
1405
- const event = this.safeString(message, 'event');
1406
- if (event === 'login') {
1407
- this.handleAuthenticate(client, message);
1408
- return;
1409
- }
1410
- if (event === 'subscribe') {
1411
- this.handleSubscriptionStatus(client, message);
1412
- return;
1413
- }
1414
- if (event === 'unsubscribe') {
1415
- this.handleUnSubscriptionStatus(client, message);
1416
- return;
1417
- }
1418
- const data = this.safeDict(message, 'arg', {});
1419
- const channel = this.safeString(data, 'channel');
1420
- if (channel === 'ticker') {
1421
- this.handleTicker(client, message);
1422
- }
1423
- if (channel.indexOf('candle') >= 0) {
1424
- this.handleOHLCV(client, message);
1425
- }
1426
- if (channel.indexOf('books') >= 0) {
1427
- this.handleOrderBook(client, message);
1428
- }
1429
- if (channel === 'trade') {
1430
- this.handleTrades(client, message);
1431
- }
1432
- if (channel === 'account') {
1433
- this.handleBalance(client, message);
1434
- }
1435
- if ((channel === 'orders') || (channel === 'ordersAlgo')) {
1436
- this.handleOrder(client, message);
1437
- }
1438
- if (channel === 'positions') {
1439
- this.handlePositions(client, message);
1440
- }
1441
- }
1442
- ping(client) {
1443
- return 'ping';
1444
- }
1445
- handlePong(client, message) {
1446
- client.lastPong = this.milliseconds();
1447
- return message;
1448
- }
1449
- handleSubscriptionStatus(client, message) {
1450
- return message;
1451
- }
1452
- handleUnSubscriptionStatus(client, message) {
1453
- let argsList = this.safeList(message, 'args');
1454
- if (argsList === undefined) {
1455
- argsList = [this.safeDict(message, 'arg', {})];
1456
- }
1457
- for (let i = 0; i < argsList.length; i++) {
1458
- const arg = argsList[i];
1459
- const channel = this.safeString(arg, 'channel');
1460
- if (channel === 'books') {
1461
- this.handleOrderBookUnSubscription(client, message);
1462
- }
1463
- else if (channel === 'trade') {
1464
- this.handleTradesUnSubscription(client, message);
1465
- }
1466
- else if (channel === 'ticker') {
1467
- this.handleTickerUnSubscription(client, message);
1468
- }
1469
- else if (channel.startsWith('candle')) {
1470
- this.handleOHLCVUnSubscription(client, message);
1471
- }
1472
- }
1473
- return message;
1474
- }
1475
- handleOrderBookUnSubscription(client, message) {
1476
- const arg = this.safeDict(message, 'arg', {});
1477
- const instType = this.safeStringLower(arg, 'instType');
1478
- const type = (instType === 'sp') ? 'spot' : 'swap';
1479
- const instId = this.safeString(arg, 'instId');
1480
- const market = this.safeMarket(instId, undefined, undefined, type);
1481
- const symbol = market['symbol'];
1482
- const messageHash = 'unsubscribe:orderbook:' + market['symbol'];
1483
- const subMessageHash = 'orderbook:' + symbol;
1484
- if (symbol in this.orderbooks) {
1485
- delete this.orderbooks[symbol];
1486
- }
1487
- if (subMessageHash in client.subscriptions) {
1488
- delete client.subscriptions[subMessageHash];
1489
- }
1490
- if (messageHash in client.subscriptions) {
1491
- delete client.subscriptions[messageHash];
1492
- }
1493
- const error = new errors.UnsubscribeError(this.id + ' orderbook ' + symbol);
1494
- client.reject(error, subMessageHash);
1495
- client.resolve(true, messageHash);
1496
- }
1497
- handleTradesUnSubscription(client, message) {
1498
- const arg = this.safeDict(message, 'arg', {});
1499
- const instType = this.safeStringLower(arg, 'instType');
1500
- const type = (instType === 'sp') ? 'spot' : 'swap';
1501
- const instId = this.safeString(arg, 'instId');
1502
- const market = this.safeMarket(instId, undefined, undefined, type);
1503
- const symbol = market['symbol'];
1504
- const messageHash = 'unsubscribe:trade:' + market['symbol'];
1505
- const subMessageHash = 'trade:' + symbol;
1506
- if (symbol in this.trades) {
1507
- delete this.trades[symbol];
1508
- }
1509
- if (subMessageHash in client.subscriptions) {
1510
- delete client.subscriptions[subMessageHash];
1511
- }
1512
- if (messageHash in client.subscriptions) {
1513
- delete client.subscriptions[messageHash];
1514
- }
1515
- const error = new errors.UnsubscribeError(this.id + ' trades ' + symbol);
1516
- client.reject(error, subMessageHash);
1517
- client.resolve(true, messageHash);
1518
- }
1519
- handleTickerUnSubscription(client, message) {
1520
- const arg = this.safeDict(message, 'arg', {});
1521
- const instType = this.safeStringLower(arg, 'instType');
1522
- const type = (instType === 'sp') ? 'spot' : 'swap';
1523
- const instId = this.safeString(arg, 'instId');
1524
- const market = this.safeMarket(instId, undefined, undefined, type);
1525
- const symbol = market['symbol'];
1526
- const messageHash = 'unsubscribe:ticker:' + market['symbol'];
1527
- const subMessageHash = 'ticker:' + symbol;
1528
- if (symbol in this.tickers) {
1529
- delete this.tickers[symbol];
1530
- }
1531
- if (subMessageHash in client.subscriptions) {
1532
- delete client.subscriptions[subMessageHash];
1533
- }
1534
- if (messageHash in client.subscriptions) {
1535
- delete client.subscriptions[messageHash];
1536
- }
1537
- const error = new errors.UnsubscribeError(this.id + ' ticker ' + symbol);
1538
- client.reject(error, subMessageHash);
1539
- client.resolve(true, messageHash);
1540
- }
1541
- handleOHLCVUnSubscription(client, message) {
1542
- const arg = this.safeDict(message, 'arg', {});
1543
- const instType = this.safeStringLower(arg, 'instType');
1544
- const type = (instType === 'sp') ? 'spot' : 'swap';
1545
- const instId = this.safeString(arg, 'instId');
1546
- const channel = this.safeString(arg, 'channel');
1547
- const interval = channel.replace('candle', '');
1548
- const timeframes = this.safeDict(this.options, 'timeframesForWs');
1549
- const timeframe = this.findTimeframe(interval, timeframes);
1550
- const market = this.safeMarket(instId, undefined, undefined, type);
1551
- const symbol = market['symbol'];
1552
- const messageHash = 'unsubscribe:ohlcv:' + timeframe + ':' + market['symbol'];
1553
- const subMessageHash = 'ohlcv:' + symbol + ':' + timeframe;
1554
- if (symbol in this.ohlcvs) {
1555
- if (timeframe in this.ohlcvs[symbol]) {
1556
- delete this.ohlcvs[symbol][timeframe];
1557
- }
1558
- }
1559
- this.cleanUnsubscription(client, subMessageHash, messageHash);
1560
- }
1561
- }
1562
-
1563
- exports["default"] = coincatch;