ccxt 4.5.1 → 4.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +110 -112
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +1 -9
  4. package/dist/cjs/src/ascendex.js +1 -1
  5. package/dist/cjs/src/base/Exchange.js +11 -0
  6. package/dist/cjs/src/binance.js +25 -25
  7. package/dist/cjs/src/bitget.js +2 -2
  8. package/dist/cjs/src/coincatch.js +2 -2
  9. package/dist/cjs/src/gate.js +27 -12
  10. package/dist/cjs/src/gemini.js +3 -3
  11. package/dist/cjs/src/htx.js +4 -4
  12. package/dist/cjs/src/indodax.js +11 -12
  13. package/dist/cjs/src/kucoinfutures.js +8 -8
  14. package/dist/cjs/src/mexc.js +30 -1
  15. package/dist/cjs/src/okx.js +19 -5
  16. package/dist/cjs/src/poloniex.js +1 -1
  17. package/dist/cjs/src/pro/binance.js +3 -3
  18. package/dist/cjs/src/pro/bitfinex.js +140 -0
  19. package/dist/cjs/src/pro/bitget.js +222 -42
  20. package/dist/cjs/src/pro/bitmart.js +1 -1
  21. package/dist/cjs/src/pro/bybit.js +3 -3
  22. package/dist/cjs/src/pro/gemini.js +7 -2
  23. package/dist/cjs/src/pro/hyperliquid.js +5 -0
  24. package/dist/cjs/src/pro/kraken.js +4 -6
  25. package/dist/cjs/src/pro/kucoin.js +64 -0
  26. package/dist/cjs/src/pro/mexc.js +7 -3
  27. package/dist/cjs/src/zonda.js +12 -0
  28. package/js/ccxt.d.ts +2 -11
  29. package/js/ccxt.js +2 -8
  30. package/js/src/ascendex.js +1 -1
  31. package/js/src/base/Exchange.d.ts +2 -0
  32. package/js/src/base/Exchange.js +11 -0
  33. package/js/src/binance.d.ts +1 -1
  34. package/js/src/binance.js +25 -25
  35. package/js/src/bitget.js +2 -2
  36. package/js/src/coincatch.js +2 -2
  37. package/js/src/gate.js +27 -12
  38. package/js/src/gemini.js +3 -3
  39. package/js/src/htx.js +4 -4
  40. package/js/src/indodax.js +11 -12
  41. package/js/src/kucoinfutures.js +8 -8
  42. package/js/src/mexc.d.ts +3 -0
  43. package/js/src/mexc.js +30 -1
  44. package/js/src/okx.d.ts +4 -2
  45. package/js/src/okx.js +19 -5
  46. package/js/src/poloniex.js +1 -1
  47. package/js/src/pro/binance.js +3 -3
  48. package/js/src/pro/bitfinex.d.ts +30 -0
  49. package/js/src/pro/bitfinex.js +140 -0
  50. package/js/src/pro/bitget.d.ts +10 -0
  51. package/js/src/pro/bitget.js +228 -42
  52. package/js/src/pro/bitmart.js +1 -1
  53. package/js/src/pro/bybit.d.ts +2 -2
  54. package/js/src/pro/bybit.js +3 -3
  55. package/js/src/pro/gemini.d.ts +1 -1
  56. package/js/src/pro/gemini.js +7 -2
  57. package/js/src/pro/hyperliquid.js +5 -0
  58. package/js/src/pro/kraken.js +4 -6
  59. package/js/src/pro/kucoin.d.ts +22 -0
  60. package/js/src/pro/kucoin.js +64 -0
  61. package/js/src/pro/mexc.js +7 -3
  62. package/js/src/zonda.js +12 -0
  63. package/package.json +2 -1
  64. package/js/src/abstract/ellipx.d.ts +0 -28
  65. package/js/src/abstract/ellipx.js +0 -11
  66. package/js/src/abstract/vertex.d.ts +0 -22
  67. package/js/src/abstract/vertex.js +0 -11
  68. package/js/src/ellipx.d.ts +0 -237
  69. package/js/src/ellipx.js +0 -2071
  70. package/js/src/pro/vertex.d.ts +0 -104
  71. package/js/src/pro/vertex.js +0 -999
  72. package/js/src/vertex.d.ts +0 -346
  73. package/js/src/vertex.js +0 -3146
@@ -1,999 +0,0 @@
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 vertexRest from '../vertex.js';
9
- import { AuthenticationError, NotSupported, ArgumentsRequired } from '../base/errors.js';
10
- import { ArrayCacheBySymbolById, ArrayCache, ArrayCacheBySymbolBySide } from '../base/ws/Cache.js';
11
- import { Precise } from '../base/Precise.js';
12
- // ----------------------------------------------------------------------------
13
- export default class vertex extends vertexRest {
14
- describe() {
15
- return this.deepExtend(super.describe(), {
16
- 'has': {
17
- 'ws': true,
18
- 'watchBalance': false,
19
- 'watchMyTrades': true,
20
- 'watchOHLCV': false,
21
- 'watchOrderBook': true,
22
- 'watchOrders': true,
23
- 'watchTicker': true,
24
- 'watchTickers': false,
25
- 'watchTrades': true,
26
- 'watchTradesForSymbols': false,
27
- 'watchPositions': true,
28
- },
29
- 'urls': {
30
- 'api': {
31
- 'ws': 'wss://gateway.prod.vertexprotocol.com/v1/subscribe',
32
- },
33
- 'test': {
34
- 'ws': 'wss://gateway.sepolia-test.vertexprotocol.com/v1/subscribe',
35
- },
36
- },
37
- 'requiredCredentials': {
38
- 'apiKey': false,
39
- 'secret': false,
40
- 'walletAddress': true,
41
- 'privateKey': true,
42
- },
43
- 'options': {
44
- 'tradesLimit': 1000,
45
- 'ordersLimit': 1000,
46
- 'requestId': {},
47
- 'watchPositions': {
48
- 'fetchPositionsSnapshot': true,
49
- 'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
50
- },
51
- 'ws': {
52
- 'inflate': true,
53
- 'options': {
54
- 'headers': {
55
- 'Sec-WebSocket-Extensions': 'permessage-deflate', // requires permessage-deflate extension, maybe we can set this in client implementation when inflate is true
56
- },
57
- },
58
- },
59
- },
60
- 'streaming': {
61
- // 'ping': this.ping,
62
- 'keepAlive': 30000,
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
- const url = this.urls['api']['ws'];
82
- const requestId = this.requestId(url);
83
- const subscribe = {
84
- 'id': requestId,
85
- };
86
- const request = this.extend(subscribe, message);
87
- const wsOptions = {
88
- 'headers': {
89
- 'Sec-WebSocket-Extensions': 'permessage-deflate',
90
- },
91
- };
92
- this.options['ws'] = {
93
- 'options': wsOptions,
94
- };
95
- return await this.watch(url, messageHash, request, messageHash, subscribe);
96
- }
97
- /**
98
- * @method
99
- * @name vertex#watchTrades
100
- * @description watches information on multiple trades made in a market
101
- * @see https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
102
- * @param {string} symbol unified market symbol of the market trades were made in
103
- * @param {int} [since] the earliest time in ms to fetch trades for
104
- * @param {int} [limit] the maximum number of trade structures to retrieve
105
- * @param {object} [params] extra parameters specific to the exchange API endpoint
106
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
107
- */
108
- async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
109
- await this.loadMarkets();
110
- const market = this.market(symbol);
111
- const name = 'trade';
112
- const topic = market['id'] + '@' + name;
113
- const request = {
114
- 'method': 'subscribe',
115
- 'stream': {
116
- 'type': name,
117
- 'product_id': this.parseToNumeric(market['id']),
118
- },
119
- };
120
- const message = this.extend(request, params);
121
- const trades = await this.watchPublic(topic, message);
122
- if (this.newUpdates) {
123
- limit = trades.getLimit(market['symbol'], limit);
124
- }
125
- return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
126
- }
127
- handleTrade(client, message) {
128
- //
129
- // {
130
- // "type": "trade",
131
- // "timestamp": "1676151190656903000", // timestamp of the event in nanoseconds
132
- // "product_id": 1,
133
- // "price": "1000", // price the trade happened at, multiplied by 1e18
134
- // // both taker_qty and maker_qty have the same value;
135
- // // set to filled amount (min amount of taker and maker) when matching against book
136
- // // set to matched amm base amount when matching against amm
137
- // "taker_qty": "1000",
138
- // "maker_qty": "1000",
139
- // "is_taker_buyer": true,
140
- // "is_maker_amm": true // true when maker is amm
141
- // }
142
- //
143
- const topic = this.safeString(message, 'type');
144
- const marketId = this.safeString(message, 'product_id');
145
- const trade = this.parseWsTrade(message);
146
- const symbol = trade['symbol'];
147
- if (!(symbol in this.trades)) {
148
- const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
149
- const stored = new ArrayCache(limit);
150
- this.trades[symbol] = stored;
151
- }
152
- const trades = this.trades[symbol];
153
- trades.append(trade);
154
- this.trades[symbol] = trades;
155
- client.resolve(trades, marketId + '@' + topic);
156
- }
157
- /**
158
- * @method
159
- * @name vertex#watchMyTrades
160
- * @description watches information on multiple trades made by the user
161
- * @see https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
162
- * @param {string} symbol unified market symbol of the market orders were made in
163
- * @param {int} [since] the earliest time in ms to fetch orders for
164
- * @param {int} [limit] the maximum number of order structures to retrieve
165
- * @param {object} [params] extra parameters specific to the exchange API endpoint
166
- * @param {string} [params.user] user address, will default to this.walletAddress if not provided
167
- * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
168
- */
169
- async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
170
- if (symbol === undefined) {
171
- throw new ArgumentsRequired(this.id + ' watchMyTrades requires a symbol.');
172
- }
173
- await this.loadMarkets();
174
- let userAddress = undefined;
175
- [userAddress, params] = this.handlePublicAddress('watchMyTrades', params);
176
- const market = this.market(symbol);
177
- const name = 'fill';
178
- const topic = market['id'] + '@' + name;
179
- const request = {
180
- 'method': 'subscribe',
181
- 'stream': {
182
- 'type': name,
183
- 'product_id': this.parseToNumeric(market['id']),
184
- 'subaccount': this.convertAddressToSender(userAddress),
185
- },
186
- };
187
- const message = this.extend(request, params);
188
- const trades = await this.watchPublic(topic, message);
189
- if (this.newUpdates) {
190
- limit = trades.getLimit(symbol, limit);
191
- }
192
- return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
193
- }
194
- handleMyTrades(client, message) {
195
- //
196
- // {
197
- // "type": "fill",
198
- // "timestamp": "1676151190656903000", // timestamp of the event in nanoseconds
199
- // "product_id": 1,
200
- // // the subaccount that placed this order
201
- // "subaccount": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43746573743000000000000000",
202
- // // hash of the order that uniquely identifies it
203
- // "order_digest": "0xf4f7a8767faf0c7f72251a1f9e5da590f708fd9842bf8fcdeacbaa0237958fff",
204
- // // the amount filled, multiplied by 1e18
205
- // "filled_qty": "1000",
206
- // // the amount outstanding unfilled, multiplied by 1e18
207
- // "remaining_qty": "2000",
208
- // // the original order amount, multiplied by 1e18
209
- // "original_qty": "3000",
210
- // // fill price
211
- // "price": "24991000000000000000000",
212
- // // true for `taker`, false for `maker`
213
- // "is_taker": true,
214
- // "is_bid": true,
215
- // // true when matching against amm
216
- // "is_against_amm": true,
217
- // // an optional `order id` that can be provided when placing an order
218
- // "id": 100
219
- // }
220
- //
221
- const topic = this.safeString(message, 'type');
222
- const marketId = this.safeString(message, 'product_id');
223
- if (this.myTrades === undefined) {
224
- const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
225
- this.myTrades = new ArrayCacheBySymbolById(limit);
226
- }
227
- const trades = this.myTrades;
228
- const parsed = this.parseWsTrade(message);
229
- trades.append(parsed);
230
- client.resolve(trades, marketId + '@' + topic);
231
- }
232
- parseWsTrade(trade, market = undefined) {
233
- //
234
- // watchTrades
235
- // {
236
- // "type": "trade",
237
- // "timestamp": "1676151190656903000", // timestamp of the event in nanoseconds
238
- // "product_id": 1,
239
- // "price": "1000", // price the trade happened at, multiplied by 1e18
240
- // // both taker_qty and maker_qty have the same value;
241
- // // set to filled amount (min amount of taker and maker) when matching against book
242
- // // set to matched amm base amount when matching against amm
243
- // "taker_qty": "1000",
244
- // "maker_qty": "1000",
245
- // "is_taker_buyer": true,
246
- // "is_maker_amm": true // true when maker is amm
247
- // }
248
- // watchMyTrades
249
- // {
250
- // "type": "fill",
251
- // "timestamp": "1676151190656903000", // timestamp of the event in nanoseconds
252
- // "product_id": 1,
253
- // // the subaccount that placed this order
254
- // "subaccount": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43746573743000000000000000",
255
- // // hash of the order that uniquely identifies it
256
- // "order_digest": "0xf4f7a8767faf0c7f72251a1f9e5da590f708fd9842bf8fcdeacbaa0237958fff",
257
- // // the amount filled, multiplied by 1e18
258
- // "filled_qty": "1000",
259
- // // the amount outstanding unfilled, multiplied by 1e18
260
- // "remaining_qty": "2000",
261
- // // the original order amount, multiplied by 1e18
262
- // "original_qty": "3000",
263
- // // fill price
264
- // "price": "24991000000000000000000",
265
- // // true for `taker`, false for `maker`
266
- // "is_taker": true,
267
- // "is_bid": true,
268
- // // true when matching against amm
269
- // "is_against_amm": true,
270
- // // an optional `order id` that can be provided when placing an order
271
- // "id": 100
272
- // }
273
- //
274
- const marketId = this.safeString(trade, 'product_id');
275
- market = this.safeMarket(marketId, market);
276
- const symbol = market['symbol'];
277
- const price = this.convertFromX18(this.safeString(trade, 'price'));
278
- const amount = this.convertFromX18(this.safeString2(trade, 'taker_qty', 'filled_qty'));
279
- const cost = Precise.stringMul(price, amount);
280
- const timestamp = this.safeIntegerProduct(trade, 'timestamp', 0.000001);
281
- let takerOrMaker = undefined;
282
- const isTaker = this.safeBool(trade, 'is_taker');
283
- if (isTaker !== undefined) {
284
- takerOrMaker = (isTaker) ? 'taker' : 'maker';
285
- }
286
- let side = undefined;
287
- const isBid = this.safeBool(trade, 'is_bid');
288
- if (isBid !== undefined) {
289
- side = (isBid) ? 'buy' : 'sell';
290
- }
291
- return this.safeTrade({
292
- 'id': undefined,
293
- 'timestamp': timestamp,
294
- 'datetime': this.iso8601(timestamp),
295
- 'symbol': symbol,
296
- 'side': side,
297
- 'price': price,
298
- 'amount': amount,
299
- 'cost': cost,
300
- 'order': this.safeString2(trade, 'digest', 'id'),
301
- 'takerOrMaker': takerOrMaker,
302
- 'type': undefined,
303
- 'fee': undefined,
304
- 'info': trade,
305
- }, market);
306
- }
307
- /**
308
- * @method
309
- * @name vertex#watchTicker
310
- * @see https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
311
- * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
312
- * @param {string} symbol unified symbol of the market to fetch the ticker for
313
- * @param {object} [params] extra parameters specific to the exchange API endpoint
314
- * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
315
- */
316
- async watchTicker(symbol, params = {}) {
317
- await this.loadMarkets();
318
- const name = 'best_bid_offer';
319
- const market = this.market(symbol);
320
- const topic = market['id'] + '@' + name;
321
- const request = {
322
- 'method': 'subscribe',
323
- 'stream': {
324
- 'type': name,
325
- 'product_id': this.parseToNumeric(market['id']),
326
- },
327
- };
328
- const message = this.extend(request, params);
329
- return await this.watchPublic(topic, message);
330
- }
331
- parseWsTicker(ticker, market = undefined) {
332
- //
333
- // {
334
- // "type": "best_bid_offer",
335
- // "timestamp": "1676151190656903000", // timestamp of the event in nanoseconds
336
- // "product_id": 1,
337
- // "bid_price": "1000", // the highest bid price, multiplied by 1e18
338
- // "bid_qty": "1000", // quantity at the huighest bid, multiplied by 1e18.
339
- // // i.e. if this is USDC with 6 decimals, one USDC
340
- // // would be 1e12
341
- // "ask_price": "1000", // lowest ask price
342
- // "ask_qty": "1000" // quantity at the lowest ask
343
- // }
344
- //
345
- const timestamp = this.safeIntegerProduct(ticker, 'timestamp', 0.000001);
346
- return this.safeTicker({
347
- 'symbol': this.safeSymbol(undefined, market),
348
- 'timestamp': timestamp,
349
- 'datetime': this.iso8601(timestamp),
350
- 'high': this.safeString(ticker, 'high'),
351
- 'low': this.safeString(ticker, 'low'),
352
- 'bid': this.convertFromX18(this.safeString(ticker, 'bid_price')),
353
- 'bidVolume': this.convertFromX18(this.safeString(ticker, 'bid_qty')),
354
- 'ask': this.convertFromX18(this.safeString(ticker, 'ask_price')),
355
- 'askVolume': this.convertFromX18(this.safeString(ticker, 'ask_qty')),
356
- 'vwap': undefined,
357
- 'open': undefined,
358
- 'close': undefined,
359
- 'last': undefined,
360
- 'previousClose': undefined,
361
- 'change': undefined,
362
- 'percentage': undefined,
363
- 'average': undefined,
364
- 'baseVolume': undefined,
365
- 'quoteVolume': undefined,
366
- 'info': ticker,
367
- }, market);
368
- }
369
- handleTicker(client, message) {
370
- //
371
- // {
372
- // "type": "best_bid_offer",
373
- // "timestamp": "1676151190656903000", // timestamp of the event in nanoseconds
374
- // "product_id": 1,
375
- // "bid_price": "1000", // the highest bid price, multiplied by 1e18
376
- // "bid_qty": "1000", // quantity at the huighest bid, multiplied by 1e18.
377
- // // i.e. if this is USDC with 6 decimals, one USDC
378
- // // would be 1e12
379
- // "ask_price": "1000", // lowest ask price
380
- // "ask_qty": "1000" // quantity at the lowest ask
381
- // }
382
- //
383
- const marketId = this.safeString(message, 'product_id');
384
- const market = this.safeMarket(marketId);
385
- const ticker = this.parseWsTicker(message, market);
386
- ticker['symbol'] = market['symbol'];
387
- this.tickers[market['symbol']] = ticker;
388
- client.resolve(ticker, marketId + '@best_bid_offer');
389
- return message;
390
- }
391
- /**
392
- * @method
393
- * @name vertex#watchOrderBook
394
- * @see https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
395
- * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
396
- * @param {string} symbol unified symbol of the market to fetch the order book for
397
- * @param {int} [limit] the maximum amount of order book entries to return.
398
- * @param {object} [params] extra parameters specific to the exchange API endpoint
399
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
400
- */
401
- async watchOrderBook(symbol, limit = undefined, params = {}) {
402
- await this.loadMarkets();
403
- const name = 'book_depth';
404
- const market = this.market(symbol);
405
- const messageHash = market['id'] + '@' + name;
406
- const url = this.urls['api']['ws'];
407
- const requestId = this.requestId(url);
408
- const request = {
409
- 'id': requestId,
410
- 'method': 'subscribe',
411
- 'stream': {
412
- 'type': name,
413
- 'product_id': this.parseToNumeric(market['id']),
414
- },
415
- };
416
- const subscription = {
417
- 'id': requestId.toString(),
418
- 'name': name,
419
- 'symbol': symbol,
420
- 'method': this.handleOrderBookSubscription,
421
- 'limit': limit,
422
- 'params': params,
423
- };
424
- const message = this.extend(request, params);
425
- const orderbook = await this.watch(url, messageHash, message, messageHash, subscription);
426
- return orderbook.limit();
427
- }
428
- handleOrderBookSubscription(client, message, subscription) {
429
- const defaultLimit = this.safeInteger(this.options, 'watchOrderBookLimit', 1000);
430
- const limit = this.safeInteger(subscription, 'limit', defaultLimit);
431
- const symbol = this.safeString(subscription, 'symbol'); // watchOrderBook
432
- if (symbol in this.orderbooks) {
433
- delete this.orderbooks[symbol];
434
- }
435
- this.orderbooks[symbol] = this.orderBook({}, limit);
436
- this.spawn(this.fetchOrderBookSnapshot, client, message, subscription);
437
- }
438
- async fetchOrderBookSnapshot(client, message, subscription) {
439
- const symbol = this.safeString(subscription, 'symbol');
440
- const market = this.market(symbol);
441
- const messageHash = market['id'] + '@book_depth';
442
- try {
443
- const defaultLimit = this.safeInteger(this.options, 'watchOrderBookLimit', 1000);
444
- const limit = this.safeInteger(subscription, 'limit', defaultLimit);
445
- const params = this.safeValue(subscription, 'params');
446
- const snapshot = await this.fetchRestOrderBookSafe(symbol, limit, params);
447
- if (this.safeValue(this.orderbooks, symbol) === undefined) {
448
- // if the orderbook is dropped before the snapshot is received
449
- return;
450
- }
451
- const orderbook = this.orderbooks[symbol];
452
- orderbook.reset(snapshot);
453
- const messages = orderbook.cache;
454
- for (let i = 0; i < messages.length; i++) {
455
- const messageItem = messages[i];
456
- const lastTimestamp = this.parseToInt(Precise.stringDiv(this.safeString(messageItem, 'last_max_timestamp'), '1000000'));
457
- if (lastTimestamp < orderbook['timestamp']) {
458
- continue;
459
- }
460
- else {
461
- this.handleOrderBookMessage(client, messageItem, orderbook);
462
- }
463
- }
464
- this.orderbooks[symbol] = orderbook;
465
- client.resolve(orderbook, messageHash);
466
- }
467
- catch (e) {
468
- delete client.subscriptions[messageHash];
469
- client.reject(e, messageHash);
470
- }
471
- }
472
- handleOrderBook(client, message) {
473
- //
474
- //
475
- // the feed does not include a snapshot, just the deltas
476
- //
477
- // {
478
- // "type":"book_depth",
479
- // // book depth aggregates a number of events once every 50ms
480
- // // these are the minimum and maximum timestamps from
481
- // // events that contributed to this response
482
- // "min_timestamp": "1683805381879572835",
483
- // "max_timestamp": "1683805381879572835",
484
- // // the max_timestamp of the last book_depth event for this product
485
- // "last_max_timestamp": "1683805381771464799",
486
- // "product_id":1,
487
- // // changes to the bid side of the book in the form of [[price, new_qty]]
488
- // "bids":[["21594490000000000000000","51007390115411548"]],
489
- // // changes to the ask side of the book in the form of [[price, new_qty]]
490
- // "asks":[["21694490000000000000000","0"],["21695050000000000000000","0"]]
491
- // }
492
- //
493
- const marketId = this.safeString(message, 'product_id');
494
- const market = this.safeMarket(marketId);
495
- const symbol = market['symbol'];
496
- if (!(symbol in this.orderbooks)) {
497
- this.orderbooks[symbol] = this.orderBook();
498
- }
499
- const orderbook = this.orderbooks[symbol];
500
- const timestamp = this.safeInteger(orderbook, 'timestamp');
501
- if (timestamp === undefined) {
502
- // Buffer the events you receive from the stream.
503
- orderbook.cache.push(message);
504
- }
505
- else {
506
- const lastTimestamp = this.parseToInt(Precise.stringDiv(this.safeString(message, 'last_max_timestamp'), '1000000'));
507
- if (lastTimestamp > timestamp) {
508
- this.handleOrderBookMessage(client, message, orderbook);
509
- client.resolve(orderbook, marketId + '@book_depth');
510
- }
511
- }
512
- }
513
- handleOrderBookMessage(client, message, orderbook) {
514
- const timestamp = this.parseToInt(Precise.stringDiv(this.safeString(message, 'last_max_timestamp'), '1000000'));
515
- // convert from X18
516
- const data = {
517
- 'bids': [],
518
- 'asks': [],
519
- };
520
- const bids = this.safeList(message, 'bids', []);
521
- for (let i = 0; i < bids.length; i++) {
522
- const bid = bids[i];
523
- data['bids'].push([
524
- this.convertFromX18(bid[0]),
525
- this.convertFromX18(bid[1]),
526
- ]);
527
- }
528
- const asks = this.safeList(message, 'asks', []);
529
- for (let i = 0; i < asks.length; i++) {
530
- const ask = asks[i];
531
- data['asks'].push([
532
- this.convertFromX18(ask[0]),
533
- this.convertFromX18(ask[1]),
534
- ]);
535
- }
536
- this.handleDeltas(orderbook['asks'], this.safeList(data, 'asks', []));
537
- this.handleDeltas(orderbook['bids'], this.safeList(data, 'bids', []));
538
- orderbook['timestamp'] = timestamp;
539
- orderbook['datetime'] = this.iso8601(timestamp);
540
- return orderbook;
541
- }
542
- handleDelta(bookside, delta) {
543
- const price = this.safeFloat(delta, 0);
544
- const amount = this.safeFloat(delta, 1);
545
- bookside.store(price, amount);
546
- }
547
- handleDeltas(bookside, deltas) {
548
- for (let i = 0; i < deltas.length; i++) {
549
- this.handleDelta(bookside, deltas[i]);
550
- }
551
- }
552
- handleSubscriptionStatus(client, message) {
553
- //
554
- // {
555
- // "result": null,
556
- // "id": 1574649734450
557
- // }
558
- //
559
- const id = this.safeString(message, 'id');
560
- const subscriptionsById = this.indexBy(client.subscriptions, 'id');
561
- const subscription = this.safeValue(subscriptionsById, id, {});
562
- const method = this.safeValue(subscription, 'method');
563
- if (method !== undefined) {
564
- method.call(this, client, message, subscription);
565
- }
566
- return message;
567
- }
568
- /**
569
- * @method
570
- * @name vertex#watchPositions
571
- * @see https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
572
- * @description watch all open positions
573
- * @param {string[]|undefined} symbols list of unified market symbols
574
- * @param since
575
- * @param limit
576
- * @param {object} params extra parameters specific to the exchange API endpoint
577
- * @param {string} [params.user] user address, will default to this.walletAddress if not provided
578
- * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
579
- */
580
- async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
581
- await this.loadMarkets();
582
- symbols = this.marketSymbols(symbols);
583
- if (!this.isEmpty(symbols)) {
584
- if (symbols.length > 1) {
585
- throw new NotSupported(this.id + ' watchPositions require only one symbol.');
586
- }
587
- }
588
- else {
589
- throw new ArgumentsRequired(this.id + ' watchPositions require one symbol.');
590
- }
591
- let userAddress = undefined;
592
- [userAddress, params] = this.handlePublicAddress('watchPositions', params);
593
- const url = this.urls['api']['ws'];
594
- const client = this.client(url);
595
- this.setPositionsCache(client, symbols, params);
596
- const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
597
- const awaitPositionsSnapshot = this.handleOption('watchPositions', 'awaitPositionsSnapshot', true);
598
- if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
599
- const snapshot = await client.future('fetchPositionsSnapshot');
600
- return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
601
- }
602
- const name = 'position_change';
603
- const market = this.market(symbols[0]);
604
- const topic = market['id'] + '@' + name;
605
- const request = {
606
- 'method': 'subscribe',
607
- 'stream': {
608
- 'type': name,
609
- 'product_id': this.parseToNumeric(market['id']),
610
- 'subaccount': this.convertAddressToSender(userAddress),
611
- },
612
- };
613
- const message = this.extend(request, params);
614
- const newPositions = await this.watchPublic(topic, message);
615
- if (this.newUpdates) {
616
- limit = newPositions.getLimit(symbols[0], limit);
617
- }
618
- return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
619
- }
620
- setPositionsCache(client, symbols = undefined, params = {}) {
621
- const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
622
- if (fetchPositionsSnapshot) {
623
- const messageHash = 'fetchPositionsSnapshot';
624
- if (!(messageHash in client.futures)) {
625
- client.future(messageHash);
626
- this.spawn(this.loadPositionsSnapshot, client, messageHash, symbols, params);
627
- }
628
- }
629
- else {
630
- this.positions = new ArrayCacheBySymbolBySide();
631
- }
632
- }
633
- async loadPositionsSnapshot(client, messageHash, symbols, params) {
634
- const positions = await this.fetchPositions(symbols, params);
635
- this.positions = new ArrayCacheBySymbolBySide();
636
- const cache = this.positions;
637
- for (let i = 0; i < positions.length; i++) {
638
- const position = positions[i];
639
- cache.append(position);
640
- }
641
- // don't remove the future from the .futures cache
642
- const future = client.futures[messageHash];
643
- future.resolve(cache);
644
- client.resolve(cache, 'positions');
645
- }
646
- handlePositions(client, message) {
647
- //
648
- // {
649
- // "type":"position_change",
650
- // "timestamp": "1676151190656903000", // timestamp of event in nanoseconds
651
- // "product_id":1,
652
- // // whether this is a position change for the LP token for this product
653
- // "is_lp":false,
654
- // // subaccount who's position changed
655
- // "subaccount":"0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43706d00000000000000000000",
656
- // // new amount for this product
657
- // "amount":"51007390115411548",
658
- // // new quote balance for this product; zero for everything except non lp perps
659
- // // the negative of the entry cost of the perp
660
- // "v_quote_amount":"0"
661
- // }
662
- //
663
- if (this.positions === undefined) {
664
- this.positions = new ArrayCacheBySymbolBySide();
665
- }
666
- const cache = this.positions;
667
- const topic = this.safeString(message, 'type');
668
- const marketId = this.safeString(message, 'product_id');
669
- const market = this.safeMarket(marketId);
670
- const position = this.parseWsPosition(message, market);
671
- cache.append(position);
672
- client.resolve(position, marketId + '@' + topic);
673
- }
674
- parseWsPosition(position, market = undefined) {
675
- //
676
- // {
677
- // "type":"position_change",
678
- // "timestamp": "1676151190656903000", // timestamp of event in nanoseconds
679
- // "product_id":1,
680
- // // whether this is a position change for the LP token for this product
681
- // "is_lp":false,
682
- // // subaccount who's position changed
683
- // "subaccount":"0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43706d00000000000000000000",
684
- // // new amount for this product
685
- // "amount":"51007390115411548",
686
- // // new quote balance for this product; zero for everything except non lp perps
687
- // // the negative of the entry cost of the perp
688
- // "v_quote_amount":"0"
689
- // }
690
- //
691
- const marketId = this.safeString(position, 'product_id');
692
- market = this.safeMarket(marketId);
693
- const contractSize = this.convertFromX18(this.safeString(position, 'amount'));
694
- let side = 'buy';
695
- if (Precise.stringLt(contractSize, '1')) {
696
- side = 'sell';
697
- }
698
- const timestamp = this.parseToInt(Precise.stringDiv(this.safeString(position, 'timestamp'), '1000000'));
699
- return this.safePosition({
700
- 'info': position,
701
- 'id': undefined,
702
- 'symbol': this.safeString(market, 'symbol'),
703
- 'timestamp': timestamp,
704
- 'datetime': this.iso8601(timestamp),
705
- 'lastUpdateTimestamp': undefined,
706
- 'initialMargin': undefined,
707
- 'initialMarginPercentage': undefined,
708
- 'maintenanceMargin': undefined,
709
- 'maintenanceMarginPercentage': undefined,
710
- 'entryPrice': undefined,
711
- 'notional': undefined,
712
- 'leverage': undefined,
713
- 'unrealizedPnl': undefined,
714
- 'contracts': undefined,
715
- 'contractSize': this.parseNumber(contractSize),
716
- 'marginRatio': undefined,
717
- 'liquidationPrice': undefined,
718
- 'markPrice': undefined,
719
- 'lastPrice': undefined,
720
- 'collateral': undefined,
721
- 'marginMode': 'cross',
722
- 'marginType': undefined,
723
- 'side': side,
724
- 'percentage': undefined,
725
- 'hedged': undefined,
726
- 'stopLossPrice': undefined,
727
- 'takeProfitPrice': undefined,
728
- });
729
- }
730
- handleAuth(client, message) {
731
- //
732
- // { result: null, id: 1 }
733
- //
734
- const messageHash = 'authenticated';
735
- const error = this.safeString(message, 'error');
736
- if (error === undefined) {
737
- // client.resolve (message, messageHash);
738
- const future = this.safeValue(client.futures, 'authenticated');
739
- future.resolve(true);
740
- }
741
- else {
742
- const authError = new AuthenticationError(this.json(message));
743
- client.reject(authError, messageHash);
744
- // allows further authentication attempts
745
- if (messageHash in client.subscriptions) {
746
- delete client.subscriptions['authenticated'];
747
- }
748
- }
749
- }
750
- buildWsAuthenticationSig(message, chainId, verifyingContractAddress) {
751
- const messageTypes = {
752
- 'StreamAuthentication': [
753
- { 'name': 'sender', 'type': 'bytes32' },
754
- { 'name': 'expiration', 'type': 'uint64' },
755
- ],
756
- };
757
- return this.buildSig(chainId, messageTypes, message, verifyingContractAddress);
758
- }
759
- async authenticate(params = {}) {
760
- this.checkRequiredCredentials();
761
- const url = this.urls['api']['ws'];
762
- const client = this.client(url);
763
- const messageHash = 'authenticated';
764
- const future = client.future(messageHash);
765
- const authenticated = this.safeValue(client.subscriptions, messageHash);
766
- if (authenticated === undefined) {
767
- const requestId = this.requestId(url);
768
- const contracts = await this.queryContracts();
769
- const chainId = this.safeString(contracts, 'chain_id');
770
- const verifyingContractAddress = this.safeString(contracts, 'endpoint_addr');
771
- const now = this.nonce();
772
- const nonce = now + 90000;
773
- const authentication = {
774
- 'sender': this.convertAddressToSender(this.walletAddress),
775
- 'expiration': nonce,
776
- };
777
- const request = {
778
- 'id': requestId,
779
- 'method': 'authenticate',
780
- 'tx': {
781
- 'sender': authentication['sender'],
782
- 'expiration': this.numberToString(authentication['expiration']),
783
- },
784
- 'signature': this.buildWsAuthenticationSig(authentication, chainId, verifyingContractAddress),
785
- };
786
- const message = this.extend(request, params);
787
- this.watch(url, messageHash, message, messageHash);
788
- }
789
- return await future;
790
- }
791
- async watchPrivate(messageHash, message, params = {}) {
792
- await this.authenticate(params);
793
- const url = this.urls['api']['ws'];
794
- const requestId = this.requestId(url);
795
- const subscribe = {
796
- 'id': requestId,
797
- };
798
- const request = this.extend(subscribe, message);
799
- return await this.watch(url, messageHash, request, messageHash, subscribe);
800
- }
801
- /**
802
- * @method
803
- * @name vertex#watchOrders
804
- * @description watches information on multiple orders made by the user
805
- * @see https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
806
- * @param {string} symbol unified market symbol of the market orders were made in
807
- * @param {int} [since] the earliest time in ms to fetch orders for
808
- * @param {int} [limit] the maximum number of order structures to retrieve
809
- * @param {object} [params] extra parameters specific to the exchange API endpoint
810
- * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
811
- */
812
- async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
813
- if (symbol === undefined) {
814
- throw new ArgumentsRequired(this.id + ' watchOrders requires a symbol.');
815
- }
816
- this.checkRequiredCredentials();
817
- await this.loadMarkets();
818
- const name = 'order_update';
819
- const market = this.market(symbol);
820
- const topic = market['id'] + '@' + name;
821
- const request = {
822
- 'method': 'subscribe',
823
- 'stream': {
824
- 'type': name,
825
- 'subaccount': this.convertAddressToSender(this.walletAddress),
826
- 'product_id': this.parseToNumeric(market['id']),
827
- },
828
- };
829
- const message = this.extend(request, params);
830
- const orders = await this.watchPrivate(topic, message);
831
- if (this.newUpdates) {
832
- limit = orders.getLimit(symbol, limit);
833
- }
834
- return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
835
- }
836
- parseWsOrderStatus(status) {
837
- if (status !== undefined) {
838
- const statuses = {
839
- 'filled': 'open',
840
- 'placed': 'open',
841
- 'cancelled': 'canceled',
842
- };
843
- return this.safeString(statuses, status, status);
844
- }
845
- return status;
846
- }
847
- parseWsOrder(order, market = undefined) {
848
- //
849
- // {
850
- // "type": "order_update",
851
- // // timestamp of the event in nanoseconds
852
- // "timestamp": "1695081920633151000",
853
- // "product_id": 1,
854
- // // order digest
855
- // "digest": "0xf7712b63ccf70358db8f201e9bf33977423e7a63f6a16f6dab180bdd580f7c6c",
856
- // // remaining amount to be filled.
857
- // // will be `0` if the order is either fully filled or cancelled.
858
- // "amount": "82000000000000000",
859
- // // any of: "filled", "cancelled", "placed"
860
- // "reason": "filled"
861
- // // an optional `order id` that can be provided when placing an order
862
- // "id": 100
863
- // }
864
- //
865
- const marketId = this.safeString(order, 'product_id');
866
- const timestamp = this.parseToInt(Precise.stringDiv(this.safeString(order, 'timestamp'), '1000000'));
867
- const remainingString = this.convertFromX18(this.safeString(order, 'amount'));
868
- const remaining = this.parseToNumeric(remainingString);
869
- let status = this.parseWsOrderStatus(this.safeString(order, 'reason'));
870
- if (Precise.stringEq(remainingString, '0') && status === 'open') {
871
- status = 'closed';
872
- }
873
- market = this.safeMarket(marketId, market);
874
- const symbol = market['symbol'];
875
- return this.safeOrder({
876
- 'info': order,
877
- 'id': this.safeString2(order, 'digest', 'id'),
878
- 'clientOrderId': undefined,
879
- 'timestamp': timestamp,
880
- 'datetime': this.iso8601(timestamp),
881
- 'lastTradeTimestamp': undefined,
882
- 'lastUpdateTimestamp': undefined,
883
- 'symbol': symbol,
884
- 'type': undefined,
885
- 'timeInForce': undefined,
886
- 'postOnly': undefined,
887
- 'reduceOnly': undefined,
888
- 'side': undefined,
889
- 'price': undefined,
890
- 'triggerPrice': undefined,
891
- 'amount': undefined,
892
- 'cost': undefined,
893
- 'average': undefined,
894
- 'filled': undefined,
895
- 'remaining': remaining,
896
- 'status': status,
897
- 'fee': undefined,
898
- 'trades': undefined,
899
- }, market);
900
- }
901
- handleOrderUpdate(client, message) {
902
- //
903
- // {
904
- // "type": "order_update",
905
- // // timestamp of the event in nanoseconds
906
- // "timestamp": "1695081920633151000",
907
- // "product_id": 1,
908
- // // order digest
909
- // "digest": "0xf7712b63ccf70358db8f201e9bf33977423e7a63f6a16f6dab180bdd580f7c6c",
910
- // // remaining amount to be filled.
911
- // // will be `0` if the order is either fully filled or cancelled.
912
- // "amount": "82000000000000000",
913
- // // any of: "filled", "cancelled", "placed"
914
- // "reason": "filled"
915
- // // an optional `order id` that can be provided when placing an order
916
- // "id": 100
917
- // }
918
- //
919
- const topic = this.safeString(message, 'type');
920
- const marketId = this.safeString(message, 'product_id');
921
- const parsed = this.parseWsOrder(message);
922
- const symbol = this.safeString(parsed, 'symbol');
923
- const orderId = this.safeString(parsed, 'id');
924
- if (symbol !== undefined) {
925
- if (this.orders === undefined) {
926
- const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
927
- this.orders = new ArrayCacheBySymbolById(limit);
928
- }
929
- const cachedOrders = this.orders;
930
- const orders = this.safeDict(cachedOrders.hashmap, symbol, {});
931
- const order = this.safeDict(orders, orderId);
932
- if (order !== undefined) {
933
- parsed['timestamp'] = this.safeInteger(order, 'timestamp');
934
- parsed['datetime'] = this.safeString(order, 'datetime');
935
- }
936
- cachedOrders.append(parsed);
937
- client.resolve(this.orders, marketId + '@' + topic);
938
- }
939
- }
940
- handleErrorMessage(client, message) {
941
- //
942
- // {
943
- // result: null,
944
- // error: 'error parsing request: missing field `expiration`',
945
- // id: 0
946
- // }
947
- //
948
- const errorMessage = this.safeString(message, 'error');
949
- try {
950
- if (errorMessage !== undefined) {
951
- const feedback = this.id + ' ' + this.json(message);
952
- this.throwExactlyMatchedException(this.exceptions['exact'], errorMessage, feedback);
953
- }
954
- return false;
955
- }
956
- catch (error) {
957
- if (error instanceof AuthenticationError) {
958
- const messageHash = 'authenticated';
959
- client.reject(error, messageHash);
960
- if (messageHash in client.subscriptions) {
961
- delete client.subscriptions[messageHash];
962
- }
963
- }
964
- else {
965
- client.reject(error);
966
- }
967
- return true;
968
- }
969
- }
970
- handleMessage(client, message) {
971
- if (this.handleErrorMessage(client, message)) {
972
- return;
973
- }
974
- const methods = {
975
- 'trade': this.handleTrade,
976
- 'best_bid_offer': this.handleTicker,
977
- 'book_depth': this.handleOrderBook,
978
- 'fill': this.handleMyTrades,
979
- 'position_change': this.handlePositions,
980
- 'order_update': this.handleOrderUpdate,
981
- };
982
- const event = this.safeString(message, 'type');
983
- const method = this.safeValue(methods, event);
984
- if (method !== undefined) {
985
- method.call(this, client, message);
986
- return;
987
- }
988
- const requestId = this.safeString(message, 'id');
989
- if (requestId !== undefined) {
990
- this.handleSubscriptionStatus(client, message);
991
- return;
992
- }
993
- // check whether it's authentication
994
- const auth = this.safeValue(client.futures, 'authenticated');
995
- if (auth !== undefined) {
996
- this.handleAuth(client, message);
997
- }
998
- }
999
- }