ccxt 4.4.86 → 4.4.87

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 (70) hide show
  1. package/README.md +17 -5
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +11 -1
  4. package/dist/cjs/src/abstract/modetrade.js +9 -0
  5. package/dist/cjs/src/base/Exchange.js +10 -8
  6. package/dist/cjs/src/binance.js +1 -1
  7. package/dist/cjs/src/bitteam.js +31 -0
  8. package/dist/cjs/src/coinmetro.js +5 -1
  9. package/dist/cjs/src/derive.js +4 -5
  10. package/dist/cjs/src/ellipx.js +2 -3
  11. package/dist/cjs/src/gate.js +92 -76
  12. package/dist/cjs/src/htx.js +10 -8
  13. package/dist/cjs/src/hyperliquid.js +32 -16
  14. package/dist/cjs/src/kraken.js +5 -8
  15. package/dist/cjs/src/modetrade.js +2839 -0
  16. package/dist/cjs/src/okx.js +95 -2
  17. package/dist/cjs/src/okxus.js +53 -0
  18. package/dist/cjs/src/paradex.js +6 -1
  19. package/dist/cjs/src/phemex.js +4 -6
  20. package/dist/cjs/src/poloniex.js +181 -170
  21. package/dist/cjs/src/pro/modetrade.js +1334 -0
  22. package/dist/cjs/src/pro/okxus.js +38 -0
  23. package/dist/cjs/src/probit.js +18 -51
  24. package/dist/cjs/src/timex.js +5 -10
  25. package/dist/cjs/src/vertex.js +3 -4
  26. package/dist/cjs/src/whitebit.js +41 -11
  27. package/dist/cjs/src/woo.js +101 -77
  28. package/dist/cjs/src/woofipro.js +24 -21
  29. package/dist/cjs/src/xt.js +36 -44
  30. package/js/ccxt.d.ts +14 -2
  31. package/js/ccxt.js +10 -2
  32. package/js/src/abstract/modetrade.d.ts +122 -0
  33. package/js/src/abstract/modetrade.js +11 -0
  34. package/js/src/abstract/okxus.d.ts +352 -0
  35. package/js/src/abstract/okxus.js +11 -0
  36. package/js/src/base/Exchange.js +10 -8
  37. package/js/src/binance.js +1 -1
  38. package/js/src/bitteam.js +31 -0
  39. package/js/src/coinmetro.js +5 -1
  40. package/js/src/derive.js +4 -3
  41. package/js/src/ellipx.d.ts +1 -1
  42. package/js/src/ellipx.js +3 -5
  43. package/js/src/gate.js +92 -76
  44. package/js/src/htx.js +10 -8
  45. package/js/src/hyperliquid.js +32 -16
  46. package/js/src/kraken.js +5 -8
  47. package/js/src/modetrade.d.ts +475 -0
  48. package/js/src/modetrade.js +2840 -0
  49. package/js/src/okx.d.ts +24 -1
  50. package/js/src/okx.js +95 -2
  51. package/js/src/okxus.d.ts +4 -0
  52. package/js/src/okxus.js +54 -0
  53. package/js/src/paradex.js +6 -1
  54. package/js/src/phemex.js +4 -6
  55. package/js/src/poloniex.d.ts +2 -0
  56. package/js/src/poloniex.js +181 -170
  57. package/js/src/pro/modetrade.d.ts +155 -0
  58. package/js/src/pro/modetrade.js +1335 -0
  59. package/js/src/pro/okxus.d.ts +4 -0
  60. package/js/src/pro/okxus.js +39 -0
  61. package/js/src/probit.js +18 -51
  62. package/js/src/timex.js +5 -10
  63. package/js/src/vertex.js +3 -4
  64. package/js/src/whitebit.js +42 -11
  65. package/js/src/woo.d.ts +2 -0
  66. package/js/src/woo.js +101 -77
  67. package/js/src/woofipro.d.ts +2 -1
  68. package/js/src/woofipro.js +24 -21
  69. package/js/src/xt.js +36 -44
  70. package/package.json +1 -1
@@ -0,0 +1,1334 @@
1
+ 'use strict';
2
+
3
+ var modetrade$1 = require('../modetrade.js');
4
+ var errors = require('../base/errors.js');
5
+ var Cache = require('../base/ws/Cache.js');
6
+ var Precise = require('../base/Precise.js');
7
+ var crypto = require('../base/functions/crypto.js');
8
+ var ed25519 = require('../static_dependencies/noble-curves/ed25519.js');
9
+
10
+ // ----------------------------------------------------------------------------
11
+ // ----------------------------------------------------------------------------
12
+ class modetrade extends modetrade$1 {
13
+ describe() {
14
+ return this.deepExtend(super.describe(), {
15
+ 'has': {
16
+ 'ws': true,
17
+ 'watchBalance': true,
18
+ 'watchMyTrades': true,
19
+ 'watchOHLCV': true,
20
+ 'watchOrderBook': true,
21
+ 'watchOrders': true,
22
+ 'watchTicker': true,
23
+ 'watchTickers': true,
24
+ 'watchBidsAsks': true,
25
+ 'watchTrades': true,
26
+ 'watchTradesForSymbols': false,
27
+ 'watchPositions': true,
28
+ },
29
+ 'urls': {
30
+ 'api': {
31
+ 'ws': {
32
+ 'public': 'wss://ws-evm.orderly.org/ws/stream',
33
+ 'private': 'wss://ws-private-evm.orderly.org/v2/ws/private/stream',
34
+ },
35
+ },
36
+ 'test': {
37
+ 'ws': {
38
+ 'public': 'wss://testnet-ws-evm.orderly.org/ws/stream',
39
+ 'private': 'wss://testnet-ws-private-evm.orderly.org/v2/ws/private/stream',
40
+ },
41
+ },
42
+ },
43
+ 'requiredCredentials': {
44
+ 'apiKey': true,
45
+ 'secret': true,
46
+ 'accountId': true,
47
+ },
48
+ 'options': {
49
+ 'tradesLimit': 1000,
50
+ 'ordersLimit': 1000,
51
+ 'requestId': {},
52
+ 'watchPositions': {
53
+ 'fetchPositionsSnapshot': true,
54
+ 'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
55
+ },
56
+ },
57
+ 'streaming': {
58
+ 'ping': this.ping,
59
+ 'keepAlive': 10000,
60
+ },
61
+ 'exceptions': {
62
+ 'ws': {
63
+ 'exact': {
64
+ 'Auth is needed.': errors.AuthenticationError,
65
+ },
66
+ },
67
+ },
68
+ });
69
+ }
70
+ requestId(url) {
71
+ const options = this.safeDict(this.options, 'requestId', {});
72
+ const previousValue = this.safeInteger(options, url, 0);
73
+ const newValue = this.sum(previousValue, 1);
74
+ this.options['requestId'][url] = newValue;
75
+ return newValue;
76
+ }
77
+ async watchPublic(messageHash, message) {
78
+ // the default id
79
+ let id = 'OqdphuyCtYWxwzhxyLLjOWNdFP7sQt8RPWzmb5xY';
80
+ if (this.accountId !== undefined) {
81
+ id = this.accountId;
82
+ }
83
+ const url = this.urls['api']['ws']['public'] + '/' + id;
84
+ const requestId = this.requestId(url);
85
+ const subscribe = {
86
+ 'id': requestId,
87
+ };
88
+ const request = this.extend(subscribe, message);
89
+ return await this.watch(url, messageHash, request, messageHash, subscribe);
90
+ }
91
+ /**
92
+ * @method
93
+ * @name modetrade#watchOrderBook
94
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/orderbook
95
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
96
+ * @param {string} symbol unified symbol of the market to fetch the order book for
97
+ * @param {int} [limit] the maximum amount of order book entries to return.
98
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
99
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
100
+ */
101
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
102
+ await this.loadMarkets();
103
+ const name = 'orderbook';
104
+ const market = this.market(symbol);
105
+ const topic = market['id'] + '@' + name;
106
+ const request = {
107
+ 'event': 'subscribe',
108
+ 'topic': topic,
109
+ };
110
+ const message = this.extend(request, params);
111
+ const orderbook = await this.watchPublic(topic, message);
112
+ return orderbook.limit();
113
+ }
114
+ handleOrderBook(client, message) {
115
+ //
116
+ // {
117
+ // "topic": "PERP_BTC_USDC@orderbook",
118
+ // "ts": 1650121915308,
119
+ // "data": {
120
+ // "symbol": "PERP_BTC_USDC",
121
+ // "bids": [
122
+ // [
123
+ // 0.30891,
124
+ // 2469.98
125
+ // ]
126
+ // ],
127
+ // "asks": [
128
+ // [
129
+ // 0.31075,
130
+ // 2379.63
131
+ // ]
132
+ // ]
133
+ // }
134
+ // }
135
+ //
136
+ const data = this.safeDict(message, 'data', {});
137
+ const marketId = this.safeString(data, 'symbol');
138
+ const market = this.safeMarket(marketId);
139
+ const symbol = market['symbol'];
140
+ const topic = this.safeString(message, 'topic');
141
+ if (!(symbol in this.orderbooks)) {
142
+ this.orderbooks[symbol] = this.orderBook();
143
+ }
144
+ const orderbook = this.orderbooks[symbol];
145
+ const timestamp = this.safeInteger(message, 'ts');
146
+ const snapshot = this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks');
147
+ orderbook.reset(snapshot);
148
+ client.resolve(orderbook, topic);
149
+ }
150
+ /**
151
+ * @method
152
+ * @name modetrade#watchTicker
153
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/24-hour-ticker
154
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
155
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
156
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
157
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
158
+ */
159
+ async watchTicker(symbol, params = {}) {
160
+ await this.loadMarkets();
161
+ const name = 'ticker';
162
+ const market = this.market(symbol);
163
+ symbol = market['symbol'];
164
+ const topic = market['id'] + '@' + name;
165
+ const request = {
166
+ 'event': 'subscribe',
167
+ 'topic': topic,
168
+ };
169
+ const message = this.extend(request, params);
170
+ return await this.watchPublic(topic, message);
171
+ }
172
+ parseWsTicker(ticker, market = undefined) {
173
+ //
174
+ // {
175
+ // "symbol": "PERP_BTC_USDC",
176
+ // "open": 19441.5,
177
+ // "close": 20147.07,
178
+ // "high": 20761.87,
179
+ // "low": 19320.54,
180
+ // "volume": 2481.103,
181
+ // "amount": 50037935.0286,
182
+ // "count": 3689
183
+ // }
184
+ //
185
+ return this.safeTicker({
186
+ 'symbol': this.safeSymbol(undefined, market),
187
+ 'timestamp': undefined,
188
+ 'datetime': undefined,
189
+ 'high': this.safeString(ticker, 'high'),
190
+ 'low': this.safeString(ticker, 'low'),
191
+ 'bid': undefined,
192
+ 'bidVolume': undefined,
193
+ 'ask': undefined,
194
+ 'askVolume': undefined,
195
+ 'vwap': undefined,
196
+ 'open': this.safeString(ticker, 'open'),
197
+ 'close': this.safeString(ticker, 'close'),
198
+ 'last': undefined,
199
+ 'previousClose': undefined,
200
+ 'change': undefined,
201
+ 'percentage': undefined,
202
+ 'average': undefined,
203
+ 'baseVolume': this.safeString(ticker, 'volume'),
204
+ 'quoteVolume': this.safeString(ticker, 'amount'),
205
+ 'info': ticker,
206
+ }, market);
207
+ }
208
+ handleTicker(client, message) {
209
+ //
210
+ // {
211
+ // "topic": "PERP_BTC_USDC@ticker",
212
+ // "ts": 1657120017000,
213
+ // "data": {
214
+ // "symbol": "PERP_BTC_USDC",
215
+ // "open": 19441.5,
216
+ // "close": 20147.07,
217
+ // "high": 20761.87,
218
+ // "low": 19320.54,
219
+ // "volume": 2481.103,
220
+ // "amount": 50037935.0286,
221
+ // "count": 3689
222
+ // }
223
+ // }
224
+ //
225
+ const data = this.safeDict(message, 'data', {});
226
+ const topic = this.safeString(message, 'topic');
227
+ const marketId = this.safeString(data, 'symbol');
228
+ const market = this.safeMarket(marketId);
229
+ const timestamp = this.safeInteger(message, 'ts');
230
+ data['date'] = timestamp;
231
+ const ticker = this.parseWsTicker(data, market);
232
+ ticker['symbol'] = market['symbol'];
233
+ this.tickers[market['symbol']] = ticker;
234
+ client.resolve(ticker, topic);
235
+ return message;
236
+ }
237
+ /**
238
+ * @method
239
+ * @name modetrade#watchTickers
240
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/24-hour-tickers
241
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
242
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
243
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
244
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
245
+ */
246
+ async watchTickers(symbols = undefined, params = {}) {
247
+ await this.loadMarkets();
248
+ symbols = this.marketSymbols(symbols);
249
+ const name = 'tickers';
250
+ const topic = name;
251
+ const request = {
252
+ 'event': 'subscribe',
253
+ 'topic': topic,
254
+ };
255
+ const message = this.extend(request, params);
256
+ const tickers = await this.watchPublic(topic, message);
257
+ return this.filterByArray(tickers, 'symbol', symbols);
258
+ }
259
+ handleTickers(client, message) {
260
+ //
261
+ // {
262
+ // "topic":"tickers",
263
+ // "ts":1618820615000,
264
+ // "data":[
265
+ // {
266
+ // "symbol":"PERP_NEAR_USDC",
267
+ // "open":16.297,
268
+ // "close":17.183,
269
+ // "high":24.707,
270
+ // "low":11.997,
271
+ // "volume":0,
272
+ // "amount":0,
273
+ // "count":0
274
+ // },
275
+ // ...
276
+ // ]
277
+ // }
278
+ //
279
+ const topic = this.safeString(message, 'topic');
280
+ const data = this.safeList(message, 'data', []);
281
+ const timestamp = this.safeInteger(message, 'ts');
282
+ const result = [];
283
+ for (let i = 0; i < data.length; i++) {
284
+ const marketId = this.safeString(data[i], 'symbol');
285
+ const market = this.safeMarket(marketId);
286
+ const ticker = this.parseWsTicker(this.extend(data[i], { 'date': timestamp }), market);
287
+ this.tickers[market['symbol']] = ticker;
288
+ result.push(ticker);
289
+ }
290
+ client.resolve(result, topic);
291
+ }
292
+ /**
293
+ * @method
294
+ * @name modetrade#watchBidsAsks
295
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/bbos
296
+ * @description watches best bid & ask for symbols
297
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
298
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
299
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
300
+ */
301
+ async watchBidsAsks(symbols = undefined, params = {}) {
302
+ await this.loadMarkets();
303
+ symbols = this.marketSymbols(symbols);
304
+ const name = 'bbos';
305
+ const topic = name;
306
+ const request = {
307
+ 'event': 'subscribe',
308
+ 'topic': topic,
309
+ };
310
+ const message = this.extend(request, params);
311
+ const tickers = await this.watchPublic(topic, message);
312
+ return this.filterByArray(tickers, 'symbol', symbols);
313
+ }
314
+ handleBidAsk(client, message) {
315
+ //
316
+ // {
317
+ // "topic": "bbos",
318
+ // "ts": 1726212495000,
319
+ // "data": [
320
+ // {
321
+ // "symbol": "PERP_BTC_USDC",
322
+ // "ask": 0.16570,
323
+ // "askSize": 4224,
324
+ // "bid": 0.16553,
325
+ // "bidSize": 6645
326
+ // }
327
+ // ]
328
+ // }
329
+ //
330
+ const topic = this.safeString(message, 'topic');
331
+ const data = this.safeList(message, 'data', []);
332
+ const timestamp = this.safeInteger(message, 'ts');
333
+ const result = [];
334
+ for (let i = 0; i < data.length; i++) {
335
+ const ticker = this.parseWsBidAsk(this.extend(data[i], { 'ts': timestamp }));
336
+ this.tickers[ticker['symbol']] = ticker;
337
+ result.push(ticker);
338
+ }
339
+ client.resolve(result, topic);
340
+ }
341
+ parseWsBidAsk(ticker, market = undefined) {
342
+ const marketId = this.safeString(ticker, 'symbol');
343
+ market = this.safeMarket(marketId, market);
344
+ const symbol = this.safeString(market, 'symbol');
345
+ const timestamp = this.safeInteger(ticker, 'ts');
346
+ return this.safeTicker({
347
+ 'symbol': symbol,
348
+ 'timestamp': timestamp,
349
+ 'datetime': this.iso8601(timestamp),
350
+ 'ask': this.safeString(ticker, 'ask'),
351
+ 'askVolume': this.safeString(ticker, 'askSize'),
352
+ 'bid': this.safeString(ticker, 'bid'),
353
+ 'bidVolume': this.safeString(ticker, 'bidSize'),
354
+ 'info': ticker,
355
+ }, market);
356
+ }
357
+ /**
358
+ * @method
359
+ * @name modetrade#watchOHLCV
360
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
361
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/k-line
362
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
363
+ * @param {string} timeframe the length of time each candle represents
364
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
365
+ * @param {int} [limit] the maximum amount of candles to fetch
366
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
367
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
368
+ */
369
+ async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
370
+ await this.loadMarkets();
371
+ if ((timeframe !== '1m') && (timeframe !== '5m') && (timeframe !== '15m') && (timeframe !== '30m') && (timeframe !== '1h') && (timeframe !== '1d') && (timeframe !== '1w') && (timeframe !== '1M')) {
372
+ throw new errors.NotSupported(this.id + ' watchOHLCV timeframe argument must be 1m, 5m, 15m, 30m, 1h, 1d, 1w, 1M');
373
+ }
374
+ const market = this.market(symbol);
375
+ const interval = this.safeString(this.timeframes, timeframe, timeframe);
376
+ const name = 'kline';
377
+ const topic = market['id'] + '@' + name + '_' + interval;
378
+ const request = {
379
+ 'event': 'subscribe',
380
+ 'topic': topic,
381
+ };
382
+ const message = this.extend(request, params);
383
+ const ohlcv = await this.watchPublic(topic, message);
384
+ if (this.newUpdates) {
385
+ limit = ohlcv.getLimit(market['symbol'], limit);
386
+ }
387
+ return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
388
+ }
389
+ handleOHLCV(client, message) {
390
+ //
391
+ // {
392
+ // "topic":"PERP_BTC_USDC@kline_1m",
393
+ // "ts":1618822432146,
394
+ // "data":{
395
+ // "symbol":"PERP_BTC_USDC",
396
+ // "type":"1m",
397
+ // "open":56948.97,
398
+ // "close":56891.76,
399
+ // "high":56948.97,
400
+ // "low":56889.06,
401
+ // "volume":44.00947568,
402
+ // "amount":2504584.9,
403
+ // "startTime":1618822380000,
404
+ // "endTime":1618822440000
405
+ // }
406
+ // }
407
+ //
408
+ const data = this.safeDict(message, 'data', {});
409
+ const topic = this.safeString(message, 'topic');
410
+ const marketId = this.safeString(data, 'symbol');
411
+ const market = this.safeMarket(marketId);
412
+ const symbol = market['symbol'];
413
+ const interval = this.safeString(data, 'type');
414
+ const timeframe = this.findTimeframe(interval);
415
+ const parsed = [
416
+ this.safeInteger(data, 'startTime'),
417
+ this.safeNumber(data, 'open'),
418
+ this.safeNumber(data, 'high'),
419
+ this.safeNumber(data, 'low'),
420
+ this.safeNumber(data, 'close'),
421
+ this.safeNumber(data, 'volume'),
422
+ ];
423
+ this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
424
+ let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
425
+ if (stored === undefined) {
426
+ const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
427
+ stored = new Cache.ArrayCacheByTimestamp(limit);
428
+ this.ohlcvs[symbol][timeframe] = stored;
429
+ }
430
+ const ohlcvCache = this.ohlcvs[symbol][timeframe];
431
+ ohlcvCache.append(parsed);
432
+ client.resolve(ohlcvCache, topic);
433
+ }
434
+ /**
435
+ * @method
436
+ * @name modetrade#watchTrades
437
+ * @description watches information on multiple trades made in a market
438
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/trade
439
+ * @param {string} symbol unified market symbol of the market trades were made in
440
+ * @param {int} [since] the earliest time in ms to fetch trades for
441
+ * @param {int} [limit] the maximum number of trade structures to retrieve
442
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
443
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
444
+ */
445
+ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
446
+ await this.loadMarkets();
447
+ const market = this.market(symbol);
448
+ symbol = market['symbol'];
449
+ const topic = market['id'] + '@trade';
450
+ const request = {
451
+ 'event': 'subscribe',
452
+ 'topic': topic,
453
+ };
454
+ const message = this.extend(request, params);
455
+ const trades = await this.watchPublic(topic, message);
456
+ if (this.newUpdates) {
457
+ limit = trades.getLimit(market['symbol'], limit);
458
+ }
459
+ return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
460
+ }
461
+ handleTrade(client, message) {
462
+ //
463
+ // {
464
+ // "topic":"PERP_ADA_USDC@trade",
465
+ // "ts":1618820361552,
466
+ // "data":{
467
+ // "symbol":"PERP_ADA_USDC",
468
+ // "price":1.27988,
469
+ // "size":300,
470
+ // "side":"BUY",
471
+ // }
472
+ // }
473
+ //
474
+ const topic = this.safeString(message, 'topic');
475
+ const timestamp = this.safeInteger(message, 'ts');
476
+ const data = this.safeDict(message, 'data', {});
477
+ const marketId = this.safeString(data, 'symbol');
478
+ const market = this.safeMarket(marketId);
479
+ const symbol = market['symbol'];
480
+ const trade = this.parseWsTrade(this.extend(data, { 'timestamp': timestamp }), market);
481
+ if (!(symbol in this.trades)) {
482
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
483
+ const stored = new Cache.ArrayCache(limit);
484
+ this.trades[symbol] = stored;
485
+ }
486
+ const trades = this.trades[symbol];
487
+ trades.append(trade);
488
+ this.trades[symbol] = trades;
489
+ client.resolve(trades, topic);
490
+ }
491
+ parseWsTrade(trade, market = undefined) {
492
+ //
493
+ // {
494
+ // "symbol":"PERP_ADA_USDC",
495
+ // "timestamp":1618820361552,
496
+ // "price":1.27988,
497
+ // "size":300,
498
+ // "side":"BUY",
499
+ // }
500
+ // private stream
501
+ // {
502
+ // symbol: 'PERP_XRP_USDC',
503
+ // clientOrderId: '',
504
+ // orderId: 1167632251,
505
+ // type: 'MARKET',
506
+ // side: 'BUY',
507
+ // quantity: 20,
508
+ // price: 0,
509
+ // tradeId: '1715179456664012',
510
+ // executedPrice: 0.5276,
511
+ // executedQuantity: 20,
512
+ // fee: 0.006332,
513
+ // feeAsset: 'USDC',
514
+ // totalExecutedQuantity: 20,
515
+ // avgPrice: 0.5276,
516
+ // averageExecutedPrice: 0.5276,
517
+ // status: 'FILLED',
518
+ // reason: '',
519
+ // totalFee: 0.006332,
520
+ // visible: 0,
521
+ // visibleQuantity: 0,
522
+ // timestamp: 1715179456660,
523
+ // orderTag: 'CCXT',
524
+ // createdTime: 1715179456656,
525
+ // maker: false
526
+ // }
527
+ //
528
+ const marketId = this.safeString(trade, 'symbol');
529
+ market = this.safeMarket(marketId, market);
530
+ const symbol = market['symbol'];
531
+ const price = this.safeString2(trade, 'executedPrice', 'price');
532
+ const amount = this.safeString2(trade, 'executedQuantity', 'size');
533
+ const cost = Precise["default"].stringMul(price, amount);
534
+ const side = this.safeStringLower(trade, 'side');
535
+ const timestamp = this.safeInteger(trade, 'timestamp');
536
+ let takerOrMaker = undefined;
537
+ const maker = this.safeBool(trade, 'maker');
538
+ if (maker !== undefined) {
539
+ takerOrMaker = maker ? 'maker' : 'taker';
540
+ }
541
+ let fee = undefined;
542
+ const feeValue = this.safeString(trade, 'fee');
543
+ if (feeValue !== undefined) {
544
+ fee = {
545
+ 'cost': feeValue,
546
+ 'currency': this.safeCurrencyCode(this.safeString(trade, 'feeAsset')),
547
+ };
548
+ }
549
+ return this.safeTrade({
550
+ 'id': this.safeString(trade, 'tradeId'),
551
+ 'timestamp': timestamp,
552
+ 'datetime': this.iso8601(timestamp),
553
+ 'symbol': symbol,
554
+ 'side': side,
555
+ 'price': price,
556
+ 'amount': amount,
557
+ 'cost': cost,
558
+ 'order': this.safeString(trade, 'orderId'),
559
+ 'takerOrMaker': takerOrMaker,
560
+ 'type': this.safeStringLower(trade, 'type'),
561
+ 'fee': fee,
562
+ 'info': trade,
563
+ }, market);
564
+ }
565
+ handleAuth(client, message) {
566
+ //
567
+ // {
568
+ // "event": "auth",
569
+ // "success": true,
570
+ // "ts": 1657463158812
571
+ // }
572
+ //
573
+ const messageHash = 'authenticated';
574
+ const success = this.safeValue(message, 'success');
575
+ if (success) {
576
+ // client.resolve (message, messageHash);
577
+ const future = this.safeValue(client.futures, 'authenticated');
578
+ future.resolve(true);
579
+ }
580
+ else {
581
+ const error = new errors.AuthenticationError(this.json(message));
582
+ client.reject(error, messageHash);
583
+ // allows further authentication attempts
584
+ if (messageHash in client.subscriptions) {
585
+ delete client.subscriptions['authenticated'];
586
+ }
587
+ }
588
+ }
589
+ async authenticate(params = {}) {
590
+ this.checkRequiredCredentials();
591
+ const url = this.urls['api']['ws']['private'] + '/' + this.accountId;
592
+ const client = this.client(url);
593
+ const messageHash = 'authenticated';
594
+ const event = 'auth';
595
+ const future = client.future(messageHash);
596
+ const authenticated = this.safeValue(client.subscriptions, messageHash);
597
+ if (authenticated === undefined) {
598
+ const ts = this.nonce().toString();
599
+ const auth = ts;
600
+ let secret = this.secret;
601
+ if (secret.indexOf('ed25519:') >= 0) {
602
+ const parts = secret.split('ed25519:');
603
+ secret = parts[1];
604
+ }
605
+ const signature = crypto.eddsa(this.encode(auth), this.base58ToBinary(secret), ed25519.ed25519);
606
+ const request = {
607
+ 'event': event,
608
+ 'params': {
609
+ 'orderly_key': this.apiKey,
610
+ 'sign': signature,
611
+ 'timestamp': ts,
612
+ },
613
+ };
614
+ const message = this.extend(request, params);
615
+ this.watch(url, messageHash, message, messageHash);
616
+ }
617
+ return await future;
618
+ }
619
+ async watchPrivate(messageHash, message, params = {}) {
620
+ await this.authenticate(params);
621
+ const url = this.urls['api']['ws']['private'] + '/' + this.accountId;
622
+ const requestId = this.requestId(url);
623
+ const subscribe = {
624
+ 'id': requestId,
625
+ };
626
+ const request = this.extend(subscribe, message);
627
+ return await this.watch(url, messageHash, request, messageHash, subscribe);
628
+ }
629
+ async watchPrivateMultiple(messageHashes, message, params = {}) {
630
+ await this.authenticate(params);
631
+ const url = this.urls['api']['ws']['private'] + '/' + this.accountId;
632
+ const requestId = this.requestId(url);
633
+ const subscribe = {
634
+ 'id': requestId,
635
+ };
636
+ const request = this.extend(subscribe, message);
637
+ return await this.watchMultiple(url, messageHashes, request, messageHashes, subscribe);
638
+ }
639
+ /**
640
+ * @method
641
+ * @name modetrade#watchOrders
642
+ * @description watches information on multiple orders made by the user
643
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/execution-report
644
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/algo-execution-report
645
+ * @param {string} symbol unified market symbol of the market orders were made in
646
+ * @param {int} [since] the earliest time in ms to fetch orders for
647
+ * @param {int} [limit] the maximum number of order structures to retrieve
648
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
649
+ * @param {bool} [params.trigger] true if trigger order
650
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
651
+ */
652
+ async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
653
+ await this.loadMarkets();
654
+ const trigger = this.safeBool2(params, 'stop', 'trigger', false);
655
+ const topic = (trigger) ? 'algoexecutionreport' : 'executionreport';
656
+ params = this.omit(params, ['stop', 'trigger']);
657
+ let messageHash = topic;
658
+ if (symbol !== undefined) {
659
+ const market = this.market(symbol);
660
+ symbol = market['symbol'];
661
+ messageHash += ':' + symbol;
662
+ }
663
+ const request = {
664
+ 'event': 'subscribe',
665
+ 'topic': topic,
666
+ };
667
+ const message = this.extend(request, params);
668
+ const orders = await this.watchPrivate(messageHash, message);
669
+ if (this.newUpdates) {
670
+ limit = orders.getLimit(symbol, limit);
671
+ }
672
+ return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
673
+ }
674
+ /**
675
+ * @method
676
+ * @name modetrade#watchMyTrades
677
+ * @description watches information on multiple trades made by the user
678
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/execution-report
679
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/algo-execution-report
680
+ * @param {string} symbol unified market symbol of the market orders were made in
681
+ * @param {int} [since] the earliest time in ms to fetch orders for
682
+ * @param {int} [limit] the maximum number of order structures to retrieve
683
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
684
+ * @param {bool} [params.trigger] true if trigger order
685
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
686
+ */
687
+ async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
688
+ await this.loadMarkets();
689
+ const trigger = this.safeBool2(params, 'stop', 'trigger', false);
690
+ const topic = (trigger) ? 'algoexecutionreport' : 'executionreport';
691
+ params = this.omit(params, 'stop');
692
+ let messageHash = 'myTrades';
693
+ if (symbol !== undefined) {
694
+ const market = this.market(symbol);
695
+ symbol = market['symbol'];
696
+ messageHash += ':' + symbol;
697
+ }
698
+ const request = {
699
+ 'event': 'subscribe',
700
+ 'topic': topic,
701
+ };
702
+ const message = this.extend(request, params);
703
+ const orders = await this.watchPrivate(messageHash, message);
704
+ if (this.newUpdates) {
705
+ limit = orders.getLimit(symbol, limit);
706
+ }
707
+ return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
708
+ }
709
+ parseWsOrder(order, market = undefined) {
710
+ //
711
+ // {
712
+ // "symbol": "PERP_BTC_USDT",
713
+ // "clientOrderId": 0,
714
+ // "orderId": 52952826,
715
+ // "type": "LIMIT",
716
+ // "side": "SELL",
717
+ // "quantity": 0.01,
718
+ // "price": 22000,
719
+ // "tradeId": 0,
720
+ // "executedPrice": 0,
721
+ // "executedQuantity": 0,
722
+ // "fee": 0,
723
+ // "feeAsset": "USDT",
724
+ // "totalExecutedQuantity": 0,
725
+ // "status": "NEW",
726
+ // "reason": '',
727
+ // "orderTag": "default",
728
+ // "totalFee": 0,
729
+ // "visible": 0.01,
730
+ // "timestamp": 1657515556799,
731
+ // "reduceOnly": false,
732
+ // "maker": false
733
+ // }
734
+ // algo order
735
+ // {
736
+ // "symbol":"PERP_MATIC_USDC",
737
+ // "rootAlgoOrderId":123,
738
+ // "parentAlgoOrderId":123,
739
+ // "algoOrderId":123,
740
+ // "orderTag":"some tags",
741
+ // "algoType": "STOP",
742
+ // "clientOrderId":"client_id",
743
+ // "type":"LIMIT",
744
+ // "side":"BUY",
745
+ // "quantity":7029.0,
746
+ // "price":0.7699,
747
+ // "tradeId":0,
748
+ // "triggerTradePrice":0,
749
+ // "triggerTime":1234567,
750
+ // "triggered": false,
751
+ // "activated": false,
752
+ // "executedPrice":0.0,
753
+ // "executedQuantity":0.0,
754
+ // "fee":0.0,
755
+ // "feeAsset":"USDC",
756
+ // "totalExecutedQuantity":0.0,
757
+ // "averageExecutedQuantity":0.0,
758
+ // "avgPrice":0,
759
+ // "triggerPrice":0.0,
760
+ // "triggerPriceType":"STOP",
761
+ // "isActivated": false,
762
+ // "status":"NEW",
763
+ // "rootAlgoStatus": "FILLED",
764
+ // "algoStatus": "FILLED",
765
+ // "reason":"",
766
+ // "totalFee":0.0,
767
+ // "visible": 7029.0,
768
+ // "visibleQuantity":7029.0,
769
+ // "timestamp":1704679472448,
770
+ // "maker":false,
771
+ // "isMaker":false,
772
+ // "createdTime":1704679472448
773
+ // }
774
+ //
775
+ const orderId = this.safeString(order, 'orderId');
776
+ const marketId = this.safeString(order, 'symbol');
777
+ market = this.market(marketId);
778
+ const symbol = market['symbol'];
779
+ const timestamp = this.safeInteger(order, 'timestamp');
780
+ const fee = {
781
+ 'cost': this.safeString(order, 'totalFee'),
782
+ 'currency': this.safeString(order, 'feeAsset'),
783
+ };
784
+ const priceString = this.safeString(order, 'price');
785
+ let price = this.safeNumber(order, 'price');
786
+ const avgPrice = this.safeNumber(order, 'avgPrice');
787
+ if (Precise["default"].stringEq(priceString, '0') && (avgPrice !== undefined)) {
788
+ price = avgPrice;
789
+ }
790
+ const amount = this.safeString(order, 'quantity');
791
+ const side = this.safeStringLower(order, 'side');
792
+ const type = this.safeStringLower(order, 'type');
793
+ const filled = this.safeNumber(order, 'totalExecutedQuantity');
794
+ const totalExecQuantity = this.safeString(order, 'totalExecutedQuantity');
795
+ let remaining = amount;
796
+ if (Precise["default"].stringGe(amount, totalExecQuantity)) {
797
+ remaining = Precise["default"].stringSub(remaining, totalExecQuantity);
798
+ }
799
+ const rawStatus = this.safeString(order, 'status');
800
+ const status = this.parseOrderStatus(rawStatus);
801
+ const trades = undefined;
802
+ const clientOrderId = this.safeString(order, 'clientOrderId');
803
+ const triggerPrice = this.safeNumber(order, 'triggerPrice');
804
+ return this.safeOrder({
805
+ 'info': order,
806
+ 'symbol': symbol,
807
+ 'id': orderId,
808
+ 'clientOrderId': clientOrderId,
809
+ 'timestamp': timestamp,
810
+ 'datetime': this.iso8601(timestamp),
811
+ 'lastTradeTimestamp': timestamp,
812
+ 'type': type,
813
+ 'timeInForce': undefined,
814
+ 'postOnly': undefined,
815
+ 'side': side,
816
+ 'price': price,
817
+ 'stopPrice': triggerPrice,
818
+ 'triggerPrice': triggerPrice,
819
+ 'amount': amount,
820
+ 'cost': undefined,
821
+ 'average': undefined,
822
+ 'filled': filled,
823
+ 'remaining': remaining,
824
+ 'status': status,
825
+ 'fee': fee,
826
+ 'trades': trades,
827
+ });
828
+ }
829
+ handleOrderUpdate(client, message) {
830
+ //
831
+ // {
832
+ // "topic": "executionreport",
833
+ // "ts": 1657515556799,
834
+ // "data": {
835
+ // "symbol": "PERP_BTC_USDT",
836
+ // "clientOrderId": 0,
837
+ // "orderId": 52952826,
838
+ // "type": "LIMIT",
839
+ // "side": "SELL",
840
+ // "quantity": 0.01,
841
+ // "price": 22000,
842
+ // "tradeId": 0,
843
+ // "executedPrice": 0,
844
+ // "executedQuantity": 0,
845
+ // "fee": 0,
846
+ // "feeAsset": "USDT",
847
+ // "totalExecutedQuantity": 0,
848
+ // "status": "NEW",
849
+ // "reason": '',
850
+ // "orderTag": "default",
851
+ // "totalFee": 0,
852
+ // "visible": 0.01,
853
+ // "timestamp": 1657515556799,
854
+ // "maker": false
855
+ // }
856
+ // }
857
+ //
858
+ const topic = this.safeString(message, 'topic');
859
+ const data = this.safeValue(message, 'data');
860
+ if (Array.isArray(data)) {
861
+ // algoexecutionreport
862
+ for (let i = 0; i < data.length; i++) {
863
+ const order = data[i];
864
+ const tradeId = this.omitZero(this.safeString(data, 'tradeId'));
865
+ if (tradeId !== undefined) {
866
+ this.handleMyTrade(client, order);
867
+ }
868
+ this.handleOrder(client, order, topic);
869
+ }
870
+ }
871
+ else {
872
+ // executionreport
873
+ const tradeId = this.omitZero(this.safeString(data, 'tradeId'));
874
+ if (tradeId !== undefined) {
875
+ this.handleMyTrade(client, data);
876
+ }
877
+ this.handleOrder(client, data, topic);
878
+ }
879
+ }
880
+ handleOrder(client, message, topic) {
881
+ const parsed = this.parseWsOrder(message);
882
+ const symbol = this.safeString(parsed, 'symbol');
883
+ const orderId = this.safeString(parsed, 'id');
884
+ if (symbol !== undefined) {
885
+ if (this.orders === undefined) {
886
+ const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
887
+ this.orders = new Cache.ArrayCacheBySymbolById(limit);
888
+ }
889
+ const cachedOrders = this.orders;
890
+ const orders = this.safeDict(cachedOrders.hashmap, symbol, {});
891
+ const order = this.safeDict(orders, orderId);
892
+ if (order !== undefined) {
893
+ const fee = this.safeValue(order, 'fee');
894
+ if (fee !== undefined) {
895
+ parsed['fee'] = fee;
896
+ }
897
+ const fees = this.safeList(order, 'fees');
898
+ if (fees !== undefined) {
899
+ parsed['fees'] = fees;
900
+ }
901
+ parsed['trades'] = this.safeList(order, 'trades');
902
+ parsed['timestamp'] = this.safeInteger(order, 'timestamp');
903
+ parsed['datetime'] = this.safeString(order, 'datetime');
904
+ }
905
+ cachedOrders.append(parsed);
906
+ client.resolve(this.orders, topic);
907
+ const messageHashSymbol = topic + ':' + symbol;
908
+ client.resolve(this.orders, messageHashSymbol);
909
+ }
910
+ }
911
+ handleMyTrade(client, message) {
912
+ //
913
+ // {
914
+ // symbol: 'PERP_XRP_USDC',
915
+ // clientOrderId: '',
916
+ // orderId: 1167632251,
917
+ // type: 'MARKET',
918
+ // side: 'BUY',
919
+ // quantity: 20,
920
+ // price: 0,
921
+ // tradeId: '1715179456664012',
922
+ // executedPrice: 0.5276,
923
+ // executedQuantity: 20,
924
+ // fee: 0.006332,
925
+ // feeAsset: 'USDC',
926
+ // totalExecutedQuantity: 20,
927
+ // avgPrice: 0.5276,
928
+ // averageExecutedPrice: 0.5276,
929
+ // status: 'FILLED',
930
+ // reason: '',
931
+ // totalFee: 0.006332,
932
+ // visible: 0,
933
+ // visibleQuantity: 0,
934
+ // timestamp: 1715179456660,
935
+ // orderTag: 'CCXT',
936
+ // createdTime: 1715179456656,
937
+ // maker: false
938
+ // }
939
+ //
940
+ const messageHash = 'myTrades';
941
+ const marketId = this.safeString(message, 'symbol');
942
+ const market = this.safeMarket(marketId);
943
+ const symbol = market['symbol'];
944
+ const trade = this.parseWsTrade(message, market);
945
+ let trades = this.myTrades;
946
+ if (trades === undefined) {
947
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
948
+ trades = new Cache.ArrayCacheBySymbolById(limit);
949
+ this.myTrades = trades;
950
+ }
951
+ trades.append(trade);
952
+ client.resolve(trades, messageHash);
953
+ const symbolSpecificMessageHash = messageHash + ':' + symbol;
954
+ client.resolve(trades, symbolSpecificMessageHash);
955
+ }
956
+ /**
957
+ * @method
958
+ * @name modetrade#watchPositions
959
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/position-push
960
+ * @description watch all open positions
961
+ * @param {string[]} [symbols] list of unified market symbols
962
+ * @param since timestamp in ms of the earliest position to fetch
963
+ * @param limit the maximum number of positions to fetch
964
+ * @param {object} params extra parameters specific to the exchange API endpoint
965
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
966
+ */
967
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
968
+ await this.loadMarkets();
969
+ const messageHashes = [];
970
+ symbols = this.marketSymbols(symbols);
971
+ if (!this.isEmpty(symbols)) {
972
+ for (let i = 0; i < symbols.length; i++) {
973
+ const symbol = symbols[i];
974
+ messageHashes.push('positions::' + symbol);
975
+ }
976
+ }
977
+ else {
978
+ messageHashes.push('positions');
979
+ }
980
+ const url = this.urls['api']['ws']['private'] + '/' + this.accountId;
981
+ const client = this.client(url);
982
+ this.setPositionsCache(client, symbols);
983
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
984
+ const awaitPositionsSnapshot = this.handleOption('watchPositions', 'awaitPositionsSnapshot', true);
985
+ if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
986
+ const snapshot = await client.future('fetchPositionsSnapshot');
987
+ return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
988
+ }
989
+ const request = {
990
+ 'event': 'subscribe',
991
+ 'topic': 'position',
992
+ };
993
+ const newPositions = await this.watchPrivateMultiple(messageHashes, request, params);
994
+ if (this.newUpdates) {
995
+ return newPositions;
996
+ }
997
+ return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
998
+ }
999
+ setPositionsCache(client, type, symbols = undefined) {
1000
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
1001
+ if (fetchPositionsSnapshot) {
1002
+ const messageHash = 'fetchPositionsSnapshot';
1003
+ if (!(messageHash in client.futures)) {
1004
+ client.future(messageHash);
1005
+ this.spawn(this.loadPositionsSnapshot, client, messageHash);
1006
+ }
1007
+ }
1008
+ else {
1009
+ this.positions = new Cache.ArrayCacheBySymbolBySide();
1010
+ }
1011
+ }
1012
+ async loadPositionsSnapshot(client, messageHash) {
1013
+ const positions = await this.fetchPositions();
1014
+ this.positions = new Cache.ArrayCacheBySymbolBySide();
1015
+ const cache = this.positions;
1016
+ for (let i = 0; i < positions.length; i++) {
1017
+ const position = positions[i];
1018
+ const contracts = this.safeString(position, 'contracts', '0');
1019
+ if (Precise["default"].stringGt(contracts, '0')) {
1020
+ cache.append(position);
1021
+ }
1022
+ }
1023
+ // don't remove the future from the .futures cache
1024
+ const future = client.futures[messageHash];
1025
+ future.resolve(cache);
1026
+ client.resolve(cache, 'positions');
1027
+ }
1028
+ handlePositions(client, message) {
1029
+ //
1030
+ // {
1031
+ // "topic":"position",
1032
+ // "ts":1705292345255,
1033
+ // "data":{
1034
+ // "positions":[
1035
+ // {
1036
+ // "symbol":"PERP_ETH_USDC",
1037
+ // "positionQty":3.1408,
1038
+ // "costPosition":5706.51952,
1039
+ // "lastSumUnitaryFunding":0.804,
1040
+ // "sumUnitaryFundingVersion":0,
1041
+ // "pendingLongQty":0.0,
1042
+ // "pendingShortQty":-1.0,
1043
+ // "settlePrice":1816.9,
1044
+ // "averageOpenPrice":1804.51490427,
1045
+ // "unsettledPnl":-2.79856,
1046
+ // "pnl24H":-338.90179488,
1047
+ // "fee24H":4.242423,
1048
+ // "markPrice":1816.2,
1049
+ // "estLiqPrice":0.0,
1050
+ // "version":179967,
1051
+ // "imrwithOrders":0.1,
1052
+ // "mmrwithOrders":0.05,
1053
+ // "mmr":0.05,
1054
+ // "imr":0.1,
1055
+ // "timestamp":1685154032762
1056
+ // }
1057
+ // ]
1058
+ // }
1059
+ // }
1060
+ //
1061
+ const data = this.safeDict(message, 'data', {});
1062
+ const rawPositions = this.safeList(data, 'positions', []);
1063
+ if (this.positions === undefined) {
1064
+ this.positions = new Cache.ArrayCacheBySymbolBySide();
1065
+ }
1066
+ const cache = this.positions;
1067
+ const newPositions = [];
1068
+ for (let i = 0; i < rawPositions.length; i++) {
1069
+ const rawPosition = rawPositions[i];
1070
+ const marketId = this.safeString(rawPosition, 'symbol');
1071
+ const market = this.safeMarket(marketId);
1072
+ const position = this.parseWsPosition(rawPosition, market);
1073
+ newPositions.push(position);
1074
+ cache.append(position);
1075
+ const messageHash = 'positions::' + market['symbol'];
1076
+ client.resolve(position, messageHash);
1077
+ }
1078
+ client.resolve(newPositions, 'positions');
1079
+ }
1080
+ parseWsPosition(position, market = undefined) {
1081
+ //
1082
+ // {
1083
+ // "symbol":"PERP_ETH_USDC",
1084
+ // "positionQty":3.1408,
1085
+ // "costPosition":5706.51952,
1086
+ // "lastSumUnitaryFunding":0.804,
1087
+ // "sumUnitaryFundingVersion":0,
1088
+ // "pendingLongQty":0.0,
1089
+ // "pendingShortQty":-1.0,
1090
+ // "settlePrice":1816.9,
1091
+ // "averageOpenPrice":1804.51490427,
1092
+ // "unsettledPnl":-2.79856,
1093
+ // "pnl24H":-338.90179488,
1094
+ // "fee24H":4.242423,
1095
+ // "markPrice":1816.2,
1096
+ // "estLiqPrice":0.0,
1097
+ // "version":179967,
1098
+ // "imrwithOrders":0.1,
1099
+ // "mmrwithOrders":0.05,
1100
+ // "mmr":0.05,
1101
+ // "imr":0.1,
1102
+ // "timestamp":1685154032762
1103
+ // }
1104
+ //
1105
+ const contract = this.safeString(position, 'symbol');
1106
+ market = this.safeMarket(contract, market);
1107
+ let size = this.safeString(position, 'positionQty');
1108
+ let side = undefined;
1109
+ if (Precise["default"].stringGt(size, '0')) {
1110
+ side = 'long';
1111
+ }
1112
+ else {
1113
+ side = 'short';
1114
+ }
1115
+ const contractSize = this.safeString(market, 'contractSize');
1116
+ const markPrice = this.safeString(position, 'markPrice');
1117
+ const timestamp = this.safeInteger(position, 'timestamp');
1118
+ const entryPrice = this.safeString(position, 'averageOpenPrice');
1119
+ const unrealisedPnl = this.safeString(position, 'unsettledPnl');
1120
+ size = Precise["default"].stringAbs(size);
1121
+ const notional = Precise["default"].stringMul(size, markPrice);
1122
+ return this.safePosition({
1123
+ 'info': position,
1124
+ 'id': undefined,
1125
+ 'symbol': this.safeString(market, 'symbol'),
1126
+ 'timestamp': timestamp,
1127
+ 'datetime': this.iso8601(timestamp),
1128
+ 'lastUpdateTimestamp': undefined,
1129
+ 'initialMargin': undefined,
1130
+ 'initialMarginPercentage': undefined,
1131
+ 'maintenanceMargin': undefined,
1132
+ 'maintenanceMarginPercentage': undefined,
1133
+ 'entryPrice': this.parseNumber(entryPrice),
1134
+ 'notional': this.parseNumber(notional),
1135
+ 'leverage': undefined,
1136
+ 'unrealizedPnl': this.parseNumber(unrealisedPnl),
1137
+ 'contracts': this.parseNumber(size),
1138
+ 'contractSize': this.parseNumber(contractSize),
1139
+ 'marginRatio': undefined,
1140
+ 'liquidationPrice': this.safeNumber(position, 'estLiqPrice'),
1141
+ 'markPrice': this.parseNumber(markPrice),
1142
+ 'lastPrice': undefined,
1143
+ 'collateral': undefined,
1144
+ 'marginMode': 'cross',
1145
+ 'marginType': undefined,
1146
+ 'side': side,
1147
+ 'percentage': undefined,
1148
+ 'hedged': undefined,
1149
+ 'stopLossPrice': undefined,
1150
+ 'takeProfitPrice': undefined,
1151
+ });
1152
+ }
1153
+ /**
1154
+ * @method
1155
+ * @name modetrade#watchBalance
1156
+ * @description watch balance and get the amount of funds available for trading or funds locked in orders
1157
+ * @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/balance
1158
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1159
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1160
+ */
1161
+ async watchBalance(params = {}) {
1162
+ await this.loadMarkets();
1163
+ const topic = 'balance';
1164
+ const messageHash = topic;
1165
+ const request = {
1166
+ 'event': 'subscribe',
1167
+ 'topic': topic,
1168
+ };
1169
+ const message = this.extend(request, params);
1170
+ return await this.watchPrivate(messageHash, message);
1171
+ }
1172
+ handleBalance(client, message) {
1173
+ //
1174
+ // {
1175
+ // "topic":"balance",
1176
+ // "ts":1651836695254,
1177
+ // "data":{
1178
+ // "balances":{
1179
+ // "USDC":{
1180
+ // "holding":5555815.47398272,
1181
+ // "frozen":0,
1182
+ // "interest":0,
1183
+ // "pendingShortQty":0,
1184
+ // "pendingExposure":0,
1185
+ // "pendingLongQty":0,
1186
+ // "pendingLongExposure":0,
1187
+ // "version":894,
1188
+ // "staked":51370692,
1189
+ // "unbonding":0,
1190
+ // "vault":0,
1191
+ // "averageOpenPrice":0.00000574,
1192
+ // "pnl24H":0,
1193
+ // "fee24H":0.01914,
1194
+ // "markPrice":0.31885
1195
+ // }
1196
+ // }
1197
+ // }
1198
+ // }
1199
+ //
1200
+ const data = this.safeDict(message, 'data', {});
1201
+ const balances = this.safeDict(data, 'balances', {});
1202
+ const keys = Object.keys(balances);
1203
+ const ts = this.safeInteger(message, 'ts');
1204
+ this.balance['info'] = data;
1205
+ this.balance['timestamp'] = ts;
1206
+ this.balance['datetime'] = this.iso8601(ts);
1207
+ for (let i = 0; i < keys.length; i++) {
1208
+ const key = keys[i];
1209
+ const value = balances[key];
1210
+ const code = this.safeCurrencyCode(key);
1211
+ const account = (code in this.balance) ? this.balance[code] : this.account();
1212
+ const total = this.safeString(value, 'holding');
1213
+ const used = this.safeString(value, 'frozen');
1214
+ account['total'] = total;
1215
+ account['used'] = used;
1216
+ account['free'] = Precise["default"].stringSub(total, used);
1217
+ this.balance[code] = account;
1218
+ }
1219
+ this.balance = this.safeBalance(this.balance);
1220
+ client.resolve(this.balance, 'balance');
1221
+ }
1222
+ handleErrorMessage(client, message) {
1223
+ //
1224
+ // {"id":"1","event":"subscribe","success":false,"ts":1710780997216,"errorMsg":"Auth is needed."}
1225
+ //
1226
+ if (!('success' in message)) {
1227
+ return false;
1228
+ }
1229
+ const success = this.safeBool(message, 'success');
1230
+ if (success) {
1231
+ return false;
1232
+ }
1233
+ const errorMessage = this.safeString(message, 'errorMsg');
1234
+ try {
1235
+ if (errorMessage !== undefined) {
1236
+ const feedback = this.id + ' ' + this.json(message);
1237
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorMessage, feedback);
1238
+ }
1239
+ return false;
1240
+ }
1241
+ catch (error) {
1242
+ if (error instanceof errors.AuthenticationError) {
1243
+ const messageHash = 'authenticated';
1244
+ client.reject(error, messageHash);
1245
+ if (messageHash in client.subscriptions) {
1246
+ delete client.subscriptions[messageHash];
1247
+ }
1248
+ }
1249
+ else {
1250
+ client.reject(error);
1251
+ }
1252
+ return true;
1253
+ }
1254
+ }
1255
+ handleMessage(client, message) {
1256
+ if (this.handleErrorMessage(client, message)) {
1257
+ return;
1258
+ }
1259
+ const methods = {
1260
+ 'ping': this.handlePing,
1261
+ 'pong': this.handlePong,
1262
+ 'subscribe': this.handleSubscribe,
1263
+ 'orderbook': this.handleOrderBook,
1264
+ 'ticker': this.handleTicker,
1265
+ 'tickers': this.handleTickers,
1266
+ 'kline': this.handleOHLCV,
1267
+ 'trade': this.handleTrade,
1268
+ 'auth': this.handleAuth,
1269
+ 'executionreport': this.handleOrderUpdate,
1270
+ 'algoexecutionreport': this.handleOrderUpdate,
1271
+ 'position': this.handlePositions,
1272
+ 'balance': this.handleBalance,
1273
+ 'bbos': this.handleBidAsk,
1274
+ };
1275
+ const event = this.safeString(message, 'event');
1276
+ let method = this.safeValue(methods, event);
1277
+ if (method !== undefined) {
1278
+ method.call(this, client, message);
1279
+ return;
1280
+ }
1281
+ const topic = this.safeString(message, 'topic');
1282
+ if (topic !== undefined) {
1283
+ method = this.safeValue(methods, topic);
1284
+ if (method !== undefined) {
1285
+ method.call(this, client, message);
1286
+ return;
1287
+ }
1288
+ const splitTopic = topic.split('@');
1289
+ const splitLength = splitTopic.length;
1290
+ if (splitLength === 2) {
1291
+ const name = this.safeString(splitTopic, 1);
1292
+ method = this.safeValue(methods, name);
1293
+ if (method !== undefined) {
1294
+ method.call(this, client, message);
1295
+ return;
1296
+ }
1297
+ const splitName = name.split('_');
1298
+ const splitNameLength = splitTopic.length;
1299
+ if (splitNameLength === 2) {
1300
+ method = this.safeValue(methods, this.safeString(splitName, 0));
1301
+ if (method !== undefined) {
1302
+ method.call(this, client, message);
1303
+ }
1304
+ }
1305
+ }
1306
+ }
1307
+ }
1308
+ ping(client) {
1309
+ return { 'event': 'ping' };
1310
+ }
1311
+ handlePing(client, message) {
1312
+ return { 'event': 'pong' };
1313
+ }
1314
+ handlePong(client, message) {
1315
+ //
1316
+ // { event: "pong", ts: 1614667590000 }
1317
+ //
1318
+ client.lastPong = this.milliseconds();
1319
+ return message;
1320
+ }
1321
+ handleSubscribe(client, message) {
1322
+ //
1323
+ // {
1324
+ // "id": "666888",
1325
+ // "event": "subscribe",
1326
+ // "success": true,
1327
+ // "ts": 1657117712212
1328
+ // }
1329
+ //
1330
+ return message;
1331
+ }
1332
+ }
1333
+
1334
+ module.exports = modetrade;