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