ccxt 4.5.40 → 4.5.42

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 (106) hide show
  1. package/README.md +6 -5
  2. package/dist/ccxt.browser.min.js +18 -18
  3. package/dist/cjs/ccxt.js +6 -1
  4. package/dist/cjs/src/abstract/lighter.js +11 -0
  5. package/dist/cjs/src/ascendex.js +73 -1
  6. package/dist/cjs/src/base/Exchange.js +149 -17
  7. package/dist/cjs/src/base/functions/generic.js +1 -0
  8. package/dist/cjs/src/base/functions/io.js +160 -0
  9. package/dist/cjs/src/base/functions.js +6 -0
  10. package/dist/cjs/src/base/ws/Client.js +1 -0
  11. package/dist/cjs/src/base/ws/WsClient.js +1 -0
  12. package/dist/cjs/src/binance.js +1 -0
  13. package/dist/cjs/src/bingx.js +13 -3
  14. package/dist/cjs/src/bitmex.js +20 -0
  15. package/dist/cjs/src/blofin.js +2 -2
  16. package/dist/cjs/src/bybit.js +1 -1
  17. package/dist/cjs/src/coinspot.js +7 -2
  18. package/dist/cjs/src/delta.js +1 -1
  19. package/dist/cjs/src/gate.js +11 -4
  20. package/dist/cjs/src/gemini.js +76 -1
  21. package/dist/cjs/src/htx.js +2 -2
  22. package/dist/cjs/src/hyperliquid.js +20 -7
  23. package/dist/cjs/src/independentreserve.js +7 -7
  24. package/dist/cjs/src/kraken.js +1 -1
  25. package/dist/cjs/src/krakenfutures.js +96 -5
  26. package/dist/cjs/src/kucoin.js +3 -3
  27. package/dist/cjs/src/kucoinfutures.js +1 -1
  28. package/dist/cjs/src/lighter.js +2931 -0
  29. package/dist/cjs/src/mexc.js +0 -1
  30. package/dist/cjs/src/phemex.js +1 -1
  31. package/dist/cjs/src/pro/binance.js +2 -2
  32. package/dist/cjs/src/pro/bingx.js +215 -2
  33. package/dist/cjs/src/pro/bitget.js +1 -0
  34. package/dist/cjs/src/pro/defx.js +1 -1
  35. package/dist/cjs/src/pro/kucoinfutures.js +1 -1
  36. package/dist/cjs/src/pro/lighter.js +787 -0
  37. package/dist/cjs/src/pro/mexc.js +1 -1
  38. package/dist/cjs/src/pro/paradex.js +1 -1
  39. package/dist/cjs/src/static_dependencies/ethers/abi-coder.js +1 -0
  40. package/dist/cjs/src/static_dependencies/ethers/address/address.js +1 -0
  41. package/dist/cjs/src/static_dependencies/ethers/coders/abstract-coder.js +1 -0
  42. package/dist/cjs/src/static_dependencies/ethers/coders/address.js +1 -0
  43. package/dist/cjs/src/static_dependencies/ethers/coders/array.js +1 -0
  44. package/dist/cjs/src/static_dependencies/ethers/coders/bytes.js +1 -0
  45. package/dist/cjs/src/static_dependencies/ethers/coders/fixed-bytes.js +1 -0
  46. package/dist/cjs/src/static_dependencies/ethers/coders/number.js +1 -0
  47. package/dist/cjs/src/static_dependencies/ethers/fragments.js +1 -0
  48. package/dist/cjs/src/static_dependencies/ethers/index.js +1 -0
  49. package/dist/cjs/src/static_dependencies/ethers/interface.js +1 -0
  50. package/dist/cjs/src/static_dependencies/ethers/typed.js +1 -0
  51. package/dist/cjs/src/static_dependencies/ethers/utils/index.js +1 -0
  52. package/dist/cjs/src/whitebit.js +118 -16
  53. package/dist/cjs/src/woo.js +1 -1
  54. package/js/ccxt.d.ts +8 -2
  55. package/js/ccxt.js +6 -2
  56. package/js/src/abstract/gemini.d.ts +27 -0
  57. package/js/src/abstract/lighter.d.ts +53 -0
  58. package/js/src/abstract/lighter.js +11 -0
  59. package/js/src/ascendex.d.ts +12 -1
  60. package/js/src/ascendex.js +73 -1
  61. package/js/src/base/Exchange.d.ts +18 -6
  62. package/js/src/base/Exchange.js +154 -21
  63. package/js/src/base/functions/generic.js +1 -0
  64. package/js/src/base/functions/io.d.ts +32 -0
  65. package/js/src/base/functions/io.js +137 -0
  66. package/js/src/base/functions.d.ts +1 -0
  67. package/js/src/base/functions.js +1 -0
  68. package/js/src/binance.d.ts +1 -0
  69. package/js/src/binance.js +1 -0
  70. package/js/src/bingx.js +13 -3
  71. package/js/src/bitmex.js +20 -0
  72. package/js/src/blofin.js +2 -2
  73. package/js/src/bybit.js +1 -1
  74. package/js/src/coinspot.js +7 -2
  75. package/js/src/delta.js +1 -1
  76. package/js/src/gate.d.ts +1 -0
  77. package/js/src/gate.js +11 -4
  78. package/js/src/gemini.d.ts +11 -0
  79. package/js/src/gemini.js +76 -1
  80. package/js/src/htx.js +2 -2
  81. package/js/src/hyperliquid.js +20 -7
  82. package/js/src/independentreserve.js +7 -7
  83. package/js/src/kraken.js +1 -1
  84. package/js/src/krakenfutures.d.ts +1 -1
  85. package/js/src/krakenfutures.js +96 -5
  86. package/js/src/kucoin.d.ts +3 -3
  87. package/js/src/kucoin.js +3 -3
  88. package/js/src/kucoinfutures.js +1 -1
  89. package/js/src/lighter.d.ts +424 -0
  90. package/js/src/lighter.js +2930 -0
  91. package/js/src/mexc.js +0 -1
  92. package/js/src/phemex.js +1 -1
  93. package/js/src/pro/binance.js +2 -2
  94. package/js/src/pro/bingx.d.ts +17 -1
  95. package/js/src/pro/bingx.js +216 -3
  96. package/js/src/pro/bitget.js +1 -0
  97. package/js/src/pro/defx.js +1 -1
  98. package/js/src/pro/kucoinfutures.js +1 -1
  99. package/js/src/pro/lighter.d.ts +161 -0
  100. package/js/src/pro/lighter.js +786 -0
  101. package/js/src/pro/mexc.js +1 -1
  102. package/js/src/pro/paradex.js +1 -1
  103. package/js/src/whitebit.d.ts +2 -1
  104. package/js/src/whitebit.js +118 -16
  105. package/js/src/woo.js +1 -1
  106. package/package.json +1 -1
@@ -0,0 +1,786 @@
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 Precise from '../base/Precise.js';
9
+ import { ArrayCache } from '../base/ws/Cache.js';
10
+ import lighterRest from '../lighter.js';
11
+ // ---------------------------------------------------------------------------
12
+ export default class lighter extends lighterRest {
13
+ describe() {
14
+ return this.deepExtend(super.describe(), {
15
+ 'has': {
16
+ 'ws': true,
17
+ 'watchTicker': true,
18
+ 'watchMarkPrice': true,
19
+ 'watchMarkPrices': true,
20
+ 'watchTickers': true,
21
+ 'watchBidsAsks': false,
22
+ 'watchOrderBook': true,
23
+ 'watchTrades': true,
24
+ 'watchTradesForSymbols': false,
25
+ 'watchOrderBookForSymbols': false,
26
+ 'watchBalance': false,
27
+ 'watchLiquidations': true,
28
+ 'watchLiquidationsForSymbols': false,
29
+ 'watchMyLiquidations': false,
30
+ 'watchMyLiquidationsForSymbols': false,
31
+ 'watchOHLCV': false,
32
+ 'watchOHLCVForSymbols': false,
33
+ 'watchOrders': false,
34
+ 'watchMyTrades': false,
35
+ 'watchPositions': false,
36
+ 'watchFundingRate': false,
37
+ 'watchFundingRates': false,
38
+ 'unWatchOrderBook': true,
39
+ 'unWatchTicker': true,
40
+ 'unWatchTickers': true,
41
+ 'unWatchTrades': true,
42
+ 'unWatchMarkPrice': true,
43
+ 'unWatchMarkPrices': true,
44
+ },
45
+ 'urls': {
46
+ 'api': {
47
+ 'ws': 'wss://mainnet.zklighter.elliot.ai/stream',
48
+ },
49
+ 'test': {
50
+ 'ws': 'wss://testnet.zklighter.elliot.ai/stream',
51
+ },
52
+ },
53
+ 'options': {},
54
+ });
55
+ }
56
+ getMessageHash(unifiedChannel, symbol = undefined, extra = undefined) {
57
+ let hash = unifiedChannel;
58
+ if (symbol !== undefined) {
59
+ hash += '::' + symbol;
60
+ }
61
+ else {
62
+ hash += 's'; // tickers, orderbooks, ohlcvs ...
63
+ }
64
+ if (extra !== undefined) {
65
+ hash += '::' + extra;
66
+ }
67
+ return hash;
68
+ }
69
+ async subscribePublic(messageHash, params = {}) {
70
+ const url = this.urls['api']['ws'];
71
+ const request = {
72
+ 'type': 'subscribe',
73
+ };
74
+ const subscription = {
75
+ 'messageHash': messageHash,
76
+ 'params': params,
77
+ };
78
+ return await this.watch(url, messageHash, this.extend(request, params), messageHash, subscription);
79
+ }
80
+ async subscribePublicMultiple(messageHashes, params = {}) {
81
+ const url = this.urls['api']['ws'];
82
+ const request = {
83
+ 'type': 'subscribe',
84
+ };
85
+ const subscription = {
86
+ 'messageHashes': messageHashes,
87
+ 'params': params,
88
+ };
89
+ return await this.watchMultiple(url, messageHashes, this.extend(request, params), messageHashes, subscription);
90
+ }
91
+ async unsubscribePublic(messageHash, params = {}) {
92
+ const url = this.urls['api']['ws'];
93
+ const request = {
94
+ 'type': 'unsubscribe',
95
+ };
96
+ const subscription = {
97
+ 'messageHash': messageHash,
98
+ 'params': params,
99
+ };
100
+ return await this.watch(url, messageHash, this.extend(request, params), messageHash, subscription);
101
+ }
102
+ handleDelta(bookside, delta) {
103
+ const price = this.safeFloat(delta, 'price');
104
+ const amount = this.safeFloat(delta, 'size');
105
+ bookside.store(price, amount);
106
+ }
107
+ handleDeltas(bookside, deltas) {
108
+ for (let i = 0; i < deltas.length; i++) {
109
+ this.handleDelta(bookside, deltas[i]);
110
+ }
111
+ }
112
+ handleOrderBookMessage(client, message, orderbook) {
113
+ const data = this.safeDict(message, 'order_book', {});
114
+ this.handleDeltas(orderbook['asks'], this.safeList(data, 'asks', []));
115
+ this.handleDeltas(orderbook['bids'], this.safeList(data, 'bids', []));
116
+ orderbook['nonce'] = this.safeInteger(data, 'offset');
117
+ const timestamp = this.safeInteger(message, 'timestamp');
118
+ orderbook['timestamp'] = timestamp;
119
+ orderbook['datetime'] = this.iso8601(timestamp);
120
+ return orderbook;
121
+ }
122
+ handleOrderBook(client, message) {
123
+ //
124
+ // {
125
+ // "channel": "order_book:0",
126
+ // "offset": 11413309,
127
+ // "order_book": {
128
+ // "code": 0,
129
+ // "asks": [
130
+ // {
131
+ // "price": "2979.64",
132
+ // "size": "61.9487"
133
+ // }
134
+ // ],
135
+ // "bids": [
136
+ // {
137
+ // "price": "2979.36",
138
+ // "size": "0.0000"
139
+ // }
140
+ // ],
141
+ // "offset": 11413309,
142
+ // "nonce": 3107818665
143
+ // },
144
+ // "timestamp": 1763448665923,
145
+ // "type": "update/order_book"
146
+ // }
147
+ //
148
+ const data = this.safeDict(message, 'order_book', {});
149
+ const channel = this.safeString(message, 'channel', '');
150
+ const parts = channel.split(':');
151
+ const marketId = parts[1];
152
+ const market = this.safeMarket(marketId);
153
+ const symbol = market['symbol'];
154
+ const timestamp = this.safeInteger(message, 'timestamp');
155
+ if (!(symbol in this.orderbooks)) {
156
+ this.orderbooks[symbol] = this.orderBook();
157
+ }
158
+ const orderbook = this.orderbooks[symbol];
159
+ const type = this.safeString(message, 'type', '');
160
+ if (type === 'subscribed/order_book') {
161
+ const parsed = this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'size');
162
+ parsed['nonce'] = this.safeInteger(data, 'offset');
163
+ orderbook.reset(parsed);
164
+ }
165
+ else if (type === 'update/order_book') {
166
+ this.handleOrderBookMessage(client, message, orderbook);
167
+ }
168
+ const messageHash = this.getMessageHash('orderbook', symbol);
169
+ client.resolve(orderbook, messageHash);
170
+ }
171
+ /**
172
+ * @method
173
+ * @name lighter#watchOrderBook
174
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
175
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#order-book
176
+ * @param {string} symbol unified symbol of the market to fetch the order book for
177
+ * @param {int} [limit] the maximum amount of order book entries to return
178
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
179
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
180
+ */
181
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
182
+ await this.loadMarkets();
183
+ const market = this.market(symbol);
184
+ const request = {
185
+ 'channel': 'order_book/' + market['id'],
186
+ };
187
+ const messageHash = this.getMessageHash('orderbook', symbol);
188
+ const orderbook = await this.subscribePublic(messageHash, this.extend(request, params));
189
+ return orderbook.limit();
190
+ }
191
+ /**
192
+ * @method
193
+ * @name lighter#unWatchOrderBook
194
+ * @description unWatches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
195
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#order-book
196
+ * @param {string} symbol unified symbol of the market
197
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
198
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
199
+ */
200
+ async unWatchOrderBook(symbol, params = {}) {
201
+ await this.loadMarkets();
202
+ const market = this.market(symbol);
203
+ const request = {
204
+ 'channel': 'order_book/' + market['id'],
205
+ };
206
+ const messageHash = this.getMessageHash('unsubscribe', symbol);
207
+ return await this.unsubscribePublic(messageHash, this.extend(request, params));
208
+ }
209
+ handleTicker(client, message) {
210
+ //
211
+ // watchTicker
212
+ // {
213
+ // "channel": "market_stats:0",
214
+ // "market_stats": {
215
+ // "market_id": 0,
216
+ // "index_price": "3015.56",
217
+ // "mark_price": "3013.91",
218
+ // "open_interest": "122736286.659423",
219
+ // "open_interest_limit": "72057594037927936.000000",
220
+ // "funding_clamp_small": "0.0500",
221
+ // "funding_clamp_big": "4.0000",
222
+ // "last_trade_price": "3013.13",
223
+ // "current_funding_rate": "0.0012",
224
+ // "funding_rate": "0.0012",
225
+ // "funding_timestamp": 1763532000004,
226
+ // "daily_base_token_volume": 643235.2763,
227
+ // "daily_quote_token_volume": 1983505435.673896,
228
+ // "daily_price_low": 2977.42,
229
+ // "daily_price_high": 3170.81,
230
+ // "daily_price_change": -0.3061987051035322
231
+ // },
232
+ // "type": "update/market_stats"
233
+ // }
234
+ //
235
+ // watchTickers
236
+ // {
237
+ // "channel": "market_stats:all",
238
+ // "market_stats": {
239
+ // "96": {
240
+ // "market_id": 96,
241
+ // "index_price": "1.15901",
242
+ // "mark_price": "1.15954",
243
+ // "open_interest": "19392952.260530",
244
+ // "open_interest_limit": "50000000000000.000000",
245
+ // "funding_clamp_small": "0.0500",
246
+ // "funding_clamp_big": "4.0000",
247
+ // "last_trade_price": "1.15955",
248
+ // "current_funding_rate": "0.0000",
249
+ // "funding_rate": "0.0000",
250
+ // "funding_timestamp": 1763532000004,
251
+ // "daily_base_token_volume": 117634224.1,
252
+ // "daily_quote_token_volume": 136339744.383989,
253
+ // "daily_price_low": 1.15774,
254
+ // "daily_price_high": 1.16105,
255
+ // "daily_price_change": -0.004311757299805109
256
+ // }
257
+ // },
258
+ // "type": "update/market_stats"
259
+ // }
260
+ //
261
+ const data = this.safeDict(message, 'market_stats', {});
262
+ const channel = this.safeString(message, 'channel');
263
+ if (channel === 'market_stats:all') {
264
+ const marketIds = Object.keys(data);
265
+ for (let i = 0; i < marketIds.length; i++) {
266
+ const marketId = marketIds[i];
267
+ const market = this.safeMarket(marketId);
268
+ const symbol = market['symbol'];
269
+ const ticker = this.parseTicker(data[marketId], market);
270
+ this.tickers[symbol] = ticker;
271
+ client.resolve(ticker, this.getMessageHash('ticker', symbol));
272
+ client.resolve(ticker, this.getMessageHash('ticker'));
273
+ }
274
+ }
275
+ else {
276
+ const marketId = this.safeString(data, 'market_id');
277
+ const market = this.safeMarket(marketId);
278
+ const symbol = market['symbol'];
279
+ const ticker = this.parseTicker(data, market);
280
+ this.tickers[symbol] = ticker;
281
+ client.resolve(ticker, this.getMessageHash('ticker', symbol));
282
+ }
283
+ }
284
+ /**
285
+ * @method
286
+ * @name lighter#watchTicker
287
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
288
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#market-stats
289
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
290
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
291
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
292
+ */
293
+ async watchTicker(symbol, params = {}) {
294
+ await this.loadMarkets();
295
+ const market = this.market(symbol);
296
+ const request = {
297
+ 'channel': 'market_stats/' + market['id'],
298
+ };
299
+ const messageHash = this.getMessageHash('ticker', symbol);
300
+ return await this.subscribePublic(messageHash, this.extend(request, params));
301
+ }
302
+ /**
303
+ * @method
304
+ * @name lighter#unWatchTicker
305
+ * @description unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
306
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#market-stats
307
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
308
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
309
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
310
+ */
311
+ async unWatchTicker(symbol, params = {}) {
312
+ await this.loadMarkets();
313
+ const market = this.market(symbol);
314
+ const request = {
315
+ 'channel': 'market_stats/' + market['id'],
316
+ };
317
+ const messageHash = this.getMessageHash('unsubscribe', symbol);
318
+ return await this.unsubscribePublic(messageHash, this.extend(request, params));
319
+ }
320
+ /**
321
+ * @method
322
+ * @name lighter#watchTickers
323
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#market-stats
324
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
325
+ * @param {string[]} [symbols] unified symbol of the market to fetch the ticker for
326
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
327
+ * @param {string} [params.channel] the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
328
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
329
+ */
330
+ async watchTickers(symbols = undefined, params = {}) {
331
+ await this.loadMarkets();
332
+ symbols = this.marketSymbols(symbols);
333
+ const request = {
334
+ 'channel': 'market_stats/all',
335
+ };
336
+ const messageHashes = [];
337
+ if (symbols === undefined || symbols.length === 0) {
338
+ messageHashes.push(this.getMessageHash('ticker'));
339
+ }
340
+ else {
341
+ for (let i = 0; i < symbols.length; i++) {
342
+ const symbol = symbols[i];
343
+ messageHashes.push(this.getMessageHash('ticker', symbol));
344
+ }
345
+ }
346
+ const newTicker = await this.subscribePublicMultiple(messageHashes, this.extend(request, params));
347
+ if (this.newUpdates) {
348
+ const result = {};
349
+ result[newTicker['symbol']] = newTicker;
350
+ return result;
351
+ }
352
+ return this.filterByArray(this.tickers, 'symbol', symbols);
353
+ }
354
+ /**
355
+ * @method
356
+ * @name lighter#unWatchTickers
357
+ * @description unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
358
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#market-stats
359
+ * @param {string[]} [symbols] unified symbol of the market to fetch the ticker for
360
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
361
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
362
+ */
363
+ async unWatchTickers(symbols = undefined, params = {}) {
364
+ await this.loadMarkets();
365
+ const request = {
366
+ 'channel': 'market_stats/all',
367
+ };
368
+ const messageHash = this.getMessageHash('unsubscribe');
369
+ return await this.unsubscribePublic(messageHash, this.extend(request, params));
370
+ }
371
+ /**
372
+ * @method
373
+ * @name lighter#watchMarkPrice
374
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#market-stats
375
+ * @description watches a mark price
376
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
377
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
378
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
379
+ */
380
+ async watchMarkPrice(symbol, params = {}) {
381
+ return await this.watchTicker(symbol, params);
382
+ }
383
+ /**
384
+ * @method
385
+ * @name lighter#watchMarkPrices
386
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#market-stats
387
+ * @description watches mark prices
388
+ * @param {string[]} [symbols] unified symbol of the market to fetch the ticker for
389
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
390
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
391
+ */
392
+ async watchMarkPrices(symbols = undefined, params = {}) {
393
+ return await this.watchTickers(symbols, params);
394
+ }
395
+ /**
396
+ * @method
397
+ * @name lighter#unWatchMarkPrice
398
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#market-stats
399
+ * @description unWatches a mark price
400
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
401
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
402
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
403
+ */
404
+ async unWatchMarkPrice(symbol, params = {}) {
405
+ return await this.unWatchTicker(symbol, params);
406
+ }
407
+ /**
408
+ * @method
409
+ * @name lighter#unWatchMarkPrices
410
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#market-stats
411
+ * @description unWatches mark prices
412
+ * @param {string[]} [symbols] unified symbol of the market to fetch the ticker for
413
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
414
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
415
+ */
416
+ async unWatchMarkPrices(symbols = undefined, params = {}) {
417
+ return await this.unWatchTickers(symbols, params);
418
+ }
419
+ parseWsTrade(trade, market = undefined) {
420
+ //
421
+ // {
422
+ // "trade_id": 526801155,
423
+ // "tx_hash": "1998d9df580acb7540aa141cc369d6ef926d003b3062196d2007bca15f978ab208e0caae4ac5872b",
424
+ // "type": "trade",
425
+ // "market_id": 0,
426
+ // "size": "0.0346",
427
+ // "price": "3028.85",
428
+ // "usd_amount": "104.798210",
429
+ // "ask_id": 281475673670566,
430
+ // "bid_id": 562949291740362,
431
+ // "ask_client_id": 76303170,
432
+ // "bid_client_id": 27601,
433
+ // "ask_account_id": 99349,
434
+ // "bid_account_id": 243008,
435
+ // "is_maker_ask": false,
436
+ // "block_height": 102322769,
437
+ // "timestamp": 1763623734215,
438
+ // "taker_position_size_before": "0.0346",
439
+ // "taker_entry_quote_before": "104.359926",
440
+ // "taker_initial_margin_fraction_before": 500,
441
+ // "taker_position_sign_changed": true,
442
+ // "maker_fee": 20,
443
+ // "maker_position_size_before": "2.1277",
444
+ // "maker_entry_quote_before": "6444.179555",
445
+ // "maker_initial_margin_fraction_before": 200
446
+ // }
447
+ //
448
+ const timestamp = this.safeInteger(trade, 'timestamp');
449
+ const tradeId = this.safeString(trade, 'trade_id');
450
+ const priceString = this.safeString(trade, 'price');
451
+ const amountString = this.safeString(trade, 'size');
452
+ const isMakerAsk = this.safeBool(trade, 'is_maker_ask');
453
+ const side = (isMakerAsk === true) ? 'sell' : 'buy';
454
+ const makerFeeRate = this.safeString(market, 'maker_fee');
455
+ const maker = Precise.stringDiv(makerFeeRate, '100');
456
+ const feeAmount = Precise.stringMul(maker, makerFeeRate);
457
+ return this.safeTrade({
458
+ 'info': trade,
459
+ 'id': tradeId,
460
+ 'order': undefined,
461
+ 'timestamp': timestamp,
462
+ 'datetime': this.iso8601(timestamp),
463
+ 'symbol': this.safeSymbol(undefined, market),
464
+ 'type': undefined,
465
+ 'side': side,
466
+ 'takerOrMaker': 'maker',
467
+ 'price': priceString,
468
+ 'amount': amountString,
469
+ 'cost': this.safeString(trade, 'usd_amount'),
470
+ 'fee': {
471
+ 'cost': feeAmount,
472
+ 'currency': 'USDC',
473
+ },
474
+ }, market);
475
+ }
476
+ handleTrades(client, message) {
477
+ //
478
+ // {
479
+ // "channel": "trade:0",
480
+ // "liquidation_trades": [],
481
+ // "nonce": 3159738569,
482
+ // "trades": [
483
+ // {
484
+ // "trade_id": 526801155,
485
+ // "tx_hash": "1998d9df580acb7540aa141cc369d6ef926d003b3062196d2007bca15f978ab208e0caae4ac5872b",
486
+ // "type": "trade",
487
+ // "market_id": 0,
488
+ // "size": "0.0346",
489
+ // "price": "3028.85",
490
+ // "usd_amount": "104.798210",
491
+ // "ask_id": 281475673670566,
492
+ // "bid_id": 562949291740362,
493
+ // "ask_client_id": 76303170,
494
+ // "bid_client_id": 27601,
495
+ // "ask_account_id": 99349,
496
+ // "bid_account_id": 243008,
497
+ // "is_maker_ask": false,
498
+ // "block_height": 102322769,
499
+ // "timestamp": 1763623734215,
500
+ // "taker_position_size_before": "0.0346",
501
+ // "taker_entry_quote_before": "104.359926",
502
+ // "taker_initial_margin_fraction_before": 500,
503
+ // "taker_position_sign_changed": true,
504
+ // "maker_fee": 20,
505
+ // "maker_position_size_before": "2.1277",
506
+ // "maker_entry_quote_before": "6444.179555",
507
+ // "maker_initial_margin_fraction_before": 200
508
+ // }
509
+ // ],
510
+ // "type": "subscribed/trade"
511
+ // }
512
+ //
513
+ const liquidationData = this.safeList(message, 'liquidation_trades', []);
514
+ if (liquidationData.length > 0) {
515
+ this.handleLiquidation(client, message);
516
+ }
517
+ const data = this.safeList(message, 'trades', []);
518
+ const channel = this.safeString(message, 'channel', '');
519
+ const parts = channel.split(':');
520
+ const marketId = parts[1];
521
+ const market = this.safeMarket(marketId);
522
+ const symbol = market['symbol'];
523
+ let stored = this.safeValue(this.trades, symbol);
524
+ if (stored === undefined) {
525
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
526
+ stored = new ArrayCache(limit);
527
+ this.trades[symbol] = stored;
528
+ }
529
+ for (let i = 0; i < data.length; i++) {
530
+ const trade = this.parseWsTrade(data[i], market);
531
+ stored.append(trade);
532
+ }
533
+ const messageHash = this.getMessageHash('trade', symbol);
534
+ client.resolve(stored, messageHash);
535
+ }
536
+ /**
537
+ * @method
538
+ * @name lighter#watchTrades
539
+ * @description get the list of most recent trades for a particular symbol
540
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#trade
541
+ * @param {string} symbol unified symbol of the market to fetch trades for
542
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
543
+ * @param {int} [limit] the maximum amount of trades to fetch
544
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
545
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
546
+ */
547
+ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
548
+ await this.loadMarkets();
549
+ const market = this.market(symbol);
550
+ const request = {
551
+ 'channel': 'trade/' + market['id'],
552
+ };
553
+ const messageHash = this.getMessageHash('trade', symbol);
554
+ return await this.subscribePublic(messageHash, this.extend(request, params));
555
+ }
556
+ /**
557
+ * @method
558
+ * @name lighter#unWatchTrades
559
+ * @description unsubscribe from the trades channel
560
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#trade
561
+ * @param {string} symbol unified symbol of the market to fetch trades for
562
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
563
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
564
+ */
565
+ async unWatchTrades(symbol, params = {}) {
566
+ await this.loadMarkets();
567
+ const market = this.market(symbol);
568
+ const request = {
569
+ 'channel': 'trade/' + market['id'],
570
+ };
571
+ const messageHash = this.getMessageHash('unsubscribe', symbol);
572
+ return await this.unsubscribePublic(messageHash, this.extend(request, params));
573
+ }
574
+ parseWsLiquidation(liquidation, market = undefined) {
575
+ //
576
+ // {
577
+ // "trade_id": 526801155,
578
+ // "tx_hash": "1998d9df580acb7540aa141cc369d6ef926d003b3062196d2007bca15f978ab208e0caae4ac5872b",
579
+ // "type": "liquidation",
580
+ // "market_id": 0,
581
+ // "size": "0.0346",
582
+ // "price": "3028.85",
583
+ // "usd_amount": "104.798210",
584
+ // "ask_id": 281475673670566,
585
+ // "bid_id": 562949291740362,
586
+ // "ask_client_id": 76303170,
587
+ // "bid_client_id": 27601,
588
+ // "ask_account_id": 99349,
589
+ // "bid_account_id": 243008,
590
+ // "is_maker_ask": false,
591
+ // "block_height": 102322769,
592
+ // "timestamp": 1763623734215,
593
+ // "taker_position_size_before": "0.0346",
594
+ // "taker_entry_quote_before": "104.359926",
595
+ // "taker_initial_margin_fraction_before": 500,
596
+ // "taker_position_sign_changed": true,
597
+ // "maker_fee": 20,
598
+ // "maker_position_size_before": "2.1277",
599
+ // "maker_entry_quote_before": "6444.179555",
600
+ // "maker_initial_margin_fraction_before": 200
601
+ // }
602
+ //
603
+ const timestamp = this.safeInteger(liquidation, 'timestamp');
604
+ return this.safeLiquidation({
605
+ 'info': liquidation,
606
+ 'symbol': market['symbol'],
607
+ 'contracts': undefined,
608
+ 'contractSize': undefined,
609
+ 'price': this.safeString(liquidation, 'price'),
610
+ 'side': this.safeString(liquidation, 'size'),
611
+ 'baseValue': undefined,
612
+ 'quoteValue': undefined,
613
+ 'timestamp': timestamp,
614
+ 'datetime': this.iso8601(timestamp),
615
+ });
616
+ }
617
+ handleLiquidation(client, message) {
618
+ //
619
+ // {
620
+ // "channel": "trade:0",
621
+ // "liquidation_trades": [],
622
+ // "nonce": 3159738569,
623
+ // "trades": [
624
+ // {
625
+ // "trade_id": 526801155,
626
+ // "tx_hash": "1998d9df580acb7540aa141cc369d6ef926d003b3062196d2007bca15f978ab208e0caae4ac5872b",
627
+ // "type": "trade",
628
+ // "market_id": 0,
629
+ // "size": "0.0346",
630
+ // "price": "3028.85",
631
+ // "usd_amount": "104.798210",
632
+ // "ask_id": 281475673670566,
633
+ // "bid_id": 562949291740362,
634
+ // "ask_client_id": 76303170,
635
+ // "bid_client_id": 27601,
636
+ // "ask_account_id": 99349,
637
+ // "bid_account_id": 243008,
638
+ // "is_maker_ask": false,
639
+ // "block_height": 102322769,
640
+ // "timestamp": 1763623734215,
641
+ // "taker_position_size_before": "0.0346",
642
+ // "taker_entry_quote_before": "104.359926",
643
+ // "taker_initial_margin_fraction_before": 500,
644
+ // "taker_position_sign_changed": true,
645
+ // "maker_fee": 20,
646
+ // "maker_position_size_before": "2.1277",
647
+ // "maker_entry_quote_before": "6444.179555",
648
+ // "maker_initial_margin_fraction_before": 200
649
+ // }
650
+ // ],
651
+ // "type": "subscribed/trade"
652
+ // }
653
+ //
654
+ const data = this.safeList(message, 'liquidation_trades', []);
655
+ const channel = this.safeString(message, 'channel', '');
656
+ const parts = channel.split(':');
657
+ const marketId = parts[1];
658
+ const market = this.safeMarket(marketId);
659
+ const symbol = market['symbol'];
660
+ let stored = this.safeValue(this.liquidations, symbol);
661
+ if (stored === undefined) {
662
+ const limit = this.safeInteger(this.options, 'liquidationsLimit', 1000);
663
+ stored = new ArrayCache(limit);
664
+ this.liquidations[symbol] = stored;
665
+ }
666
+ for (let i = 0; i < data.length; i++) {
667
+ const liquidation = this.parseWsLiquidation(data[i], market);
668
+ stored.append(liquidation);
669
+ }
670
+ const messageHash = this.getMessageHash('liquidations', symbol);
671
+ client.resolve(stored, messageHash);
672
+ }
673
+ /**
674
+ * @method
675
+ * @name lighter#watchLiquidations
676
+ * @description watch the public liquidations of a trading pair
677
+ * @see https://apidocs.lighter.xyz/docs/websocket-reference#trade
678
+ * @param {string} symbol unified symbol of the market to fetch trades for
679
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
680
+ * @param {int} [limit] the maximum amount of trades to fetch
681
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
682
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
683
+ */
684
+ async watchLiquidations(symbol, since = undefined, limit = undefined, params = {}) {
685
+ await this.loadMarkets();
686
+ const market = this.market(symbol);
687
+ const request = {
688
+ 'channel': 'trade/' + market['id'],
689
+ };
690
+ const messageHash = this.getMessageHash('liquidations', symbol);
691
+ return await this.subscribePublic(messageHash, this.extend(request, params));
692
+ }
693
+ handleErrorMessage(client, message) {
694
+ //
695
+ // {
696
+ // "error": {
697
+ // "code": 30005,
698
+ // "message": "Invalid Channel: (marketId)"
699
+ // }
700
+ // }
701
+ //
702
+ const error = this.safeDict(message, 'error');
703
+ try {
704
+ if (error !== undefined) {
705
+ const code = this.safeString(message, 'code');
706
+ if (code !== undefined) {
707
+ const feedback = this.id + ' ' + this.json(message);
708
+ this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
709
+ }
710
+ }
711
+ }
712
+ catch (e) {
713
+ client.reject(e);
714
+ }
715
+ return true;
716
+ }
717
+ handleMessage(client, message) {
718
+ if (!this.handleErrorMessage(client, message)) {
719
+ return;
720
+ }
721
+ const type = this.safeString(message, 'type', '');
722
+ if (type === 'ping') {
723
+ this.handlePing(client, message);
724
+ return;
725
+ }
726
+ const channel = this.safeString(message, 'channel', '');
727
+ if (channel.indexOf('order_book:') >= 0) {
728
+ this.handleOrderBook(client, message);
729
+ return;
730
+ }
731
+ if (channel.indexOf('market_stats:') >= 0) {
732
+ this.handleTicker(client, message);
733
+ return;
734
+ }
735
+ if (channel.indexOf('trade:') >= 0) {
736
+ this.handleTrades(client, message);
737
+ return;
738
+ }
739
+ if (channel === '') {
740
+ this.handleSubscriptionStatus(client, message);
741
+ }
742
+ }
743
+ handleSubscriptionStatus(client, message) {
744
+ //
745
+ // {
746
+ // "session_id": "8d354239-80e0-4b77-8763-87b6fef2f768",
747
+ // "type": "connected"
748
+ // }
749
+ //
750
+ // {
751
+ // "type": "unsubscribed",
752
+ // "channel": "order_book:0"
753
+ // }
754
+ //
755
+ const type = this.safeString(message, 'type', '');
756
+ const id = this.safeString(message, 'session_id');
757
+ const subscriptionsById = this.indexBy(client.subscriptions, 'id');
758
+ const subscription = this.safeDict(subscriptionsById, id, {});
759
+ if (type === 'unsubscribed') {
760
+ this.handleUnSubscription(client, subscription);
761
+ }
762
+ return message;
763
+ }
764
+ handleUnSubscription(client, subscription) {
765
+ const messageHashes = this.safeList(subscription, 'messageHashes', []);
766
+ const subMessageHashes = this.safeList(subscription, 'subMessageHashes', []);
767
+ for (let i = 0; i < messageHashes.length; i++) {
768
+ const unsubHash = messageHashes[i];
769
+ const subHash = subMessageHashes[i];
770
+ this.cleanUnsubscription(client, subHash, unsubHash);
771
+ }
772
+ this.cleanCache(subscription);
773
+ }
774
+ handlePing(client, message) {
775
+ //
776
+ // { "type": "ping" }
777
+ //
778
+ this.spawn(this.pong, client, message);
779
+ }
780
+ async pong(client, message) {
781
+ const request = {
782
+ 'type': 'pong',
783
+ };
784
+ await client.send(request);
785
+ }
786
+ }