ccxt 4.4.77 → 4.4.80

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 (154) hide show
  1. package/README.md +8 -10
  2. package/dist/ccxt.browser.min.js +7 -7
  3. package/dist/cjs/ccxt.js +8 -4
  4. package/dist/cjs/src/abstract/ace.js +1 -1
  5. package/dist/cjs/src/abstract/apex.js +9 -0
  6. package/dist/cjs/src/ace.js +1 -1
  7. package/dist/cjs/src/apex.js +1949 -0
  8. package/dist/cjs/src/ascendex.js +25 -4
  9. package/dist/cjs/src/base/Exchange.js +42 -2
  10. package/dist/cjs/src/binance.js +9 -1
  11. package/dist/cjs/src/bingx.js +3 -3
  12. package/dist/cjs/src/bitfinex.js +64 -36
  13. package/dist/cjs/src/bitget.js +191 -138
  14. package/dist/cjs/src/bitmart.js +7 -2
  15. package/dist/cjs/src/bitmex.js +16 -8
  16. package/dist/cjs/src/bitopro.js +5 -1
  17. package/dist/cjs/src/bitrue.js +2 -1
  18. package/dist/cjs/src/bitso.js +1 -1
  19. package/dist/cjs/src/bitteam.js +2 -0
  20. package/dist/cjs/src/bitvavo.js +28 -10
  21. package/dist/cjs/src/btcalpha.js +1 -1
  22. package/dist/cjs/src/btcmarkets.js +1 -1
  23. package/dist/cjs/src/btcturk.js +1 -1
  24. package/dist/cjs/src/bybit.js +32 -16
  25. package/dist/cjs/src/cex.js +1 -1
  26. package/dist/cjs/src/coinbase.js +18 -2
  27. package/dist/cjs/src/coincatch.js +68 -0
  28. package/dist/cjs/src/coinex.js +1 -0
  29. package/dist/cjs/src/coinlist.js +1 -0
  30. package/dist/cjs/src/coinone.js +1 -0
  31. package/dist/cjs/src/delta.js +4 -0
  32. package/dist/cjs/src/deribit.js +1 -0
  33. package/dist/cjs/src/hitbtc.js +3 -0
  34. package/dist/cjs/src/hollaex.js +1 -0
  35. package/dist/cjs/src/htx.js +7 -3
  36. package/dist/cjs/src/huobijp.js +1 -0
  37. package/dist/cjs/src/hyperliquid.js +14 -4
  38. package/dist/cjs/src/kraken.js +2 -0
  39. package/dist/cjs/src/mexc.js +50 -57
  40. package/dist/cjs/src/okx.js +1 -1
  41. package/dist/cjs/src/phemex.js +2 -1
  42. package/dist/cjs/src/poloniex.js +2 -1
  43. package/dist/cjs/src/pro/apex.js +1043 -0
  44. package/dist/cjs/src/pro/binance.js +3 -3
  45. package/dist/cjs/src/pro/coinbase.js +45 -68
  46. package/dist/cjs/src/pro/gate.js +27 -2
  47. package/dist/cjs/src/pro/hollaex.js +2 -2
  48. package/dist/cjs/src/pro/p2b.js +2 -2
  49. package/dist/cjs/src/pro/tradeogre.js +283 -0
  50. package/dist/cjs/src/pro/upbit.js +43 -0
  51. package/dist/cjs/src/probit.js +1 -0
  52. package/dist/cjs/src/static_dependencies/zklink/zklink-sdk-web.js +2639 -0
  53. package/dist/cjs/src/timex.js +2 -2
  54. package/dist/cjs/src/tradeogre.js +2 -1
  55. package/dist/cjs/src/upbit.js +277 -67
  56. package/dist/cjs/src/whitebit.js +66 -12
  57. package/dist/cjs/src/woo.js +3 -1
  58. package/dist/cjs/src/xt.js +9 -0
  59. package/js/ccxt.d.ts +11 -5
  60. package/js/ccxt.js +8 -4
  61. package/js/src/abstract/apex.d.ts +34 -0
  62. package/js/src/abstract/bitmart.d.ts +1 -0
  63. package/js/src/apex.d.ts +333 -0
  64. package/js/src/apex.js +1945 -0
  65. package/js/src/ascendex.d.ts +3 -3
  66. package/js/src/ascendex.js +25 -4
  67. package/js/src/base/Exchange.d.ts +2 -0
  68. package/js/src/base/Exchange.js +42 -1
  69. package/js/src/binance.d.ts +7 -7
  70. package/js/src/binance.js +9 -1
  71. package/js/src/bingx.js +3 -3
  72. package/js/src/bitfinex.d.ts +3 -3
  73. package/js/src/bitfinex.js +64 -36
  74. package/js/src/bitflyer.d.ts +2 -2
  75. package/js/src/bitget.d.ts +2 -0
  76. package/js/src/bitget.js +191 -138
  77. package/js/src/bitmart.d.ts +5 -4
  78. package/js/src/bitmart.js +7 -2
  79. package/js/src/bitmex.d.ts +3 -3
  80. package/js/src/bitmex.js +16 -8
  81. package/js/src/bitopro.js +5 -1
  82. package/js/src/bitrue.js +2 -1
  83. package/js/src/bitso.js +1 -1
  84. package/js/src/bitteam.js +2 -0
  85. package/js/src/bitvavo.js +28 -10
  86. package/js/src/btcalpha.js +1 -1
  87. package/js/src/btcmarkets.js +1 -1
  88. package/js/src/btcturk.js +1 -1
  89. package/js/src/bybit.js +32 -16
  90. package/js/src/cex.js +1 -1
  91. package/js/src/coinbase.d.ts +4 -4
  92. package/js/src/coinbase.js +18 -2
  93. package/js/src/coinbaseexchange.d.ts +1 -1
  94. package/js/src/coincatch.d.ts +11 -0
  95. package/js/src/coincatch.js +68 -0
  96. package/js/src/coinex.js +1 -0
  97. package/js/src/coinlist.js +1 -0
  98. package/js/src/coinone.js +1 -0
  99. package/js/src/cryptocom.d.ts +4 -4
  100. package/js/src/delta.js +4 -0
  101. package/js/src/deribit.d.ts +4 -4
  102. package/js/src/deribit.js +1 -0
  103. package/js/src/derive.d.ts +3 -3
  104. package/js/src/digifinex.d.ts +4 -4
  105. package/js/src/hitbtc.js +3 -0
  106. package/js/src/hollaex.js +1 -0
  107. package/js/src/htx.d.ts +4 -4
  108. package/js/src/htx.js +7 -3
  109. package/js/src/huobijp.js +1 -0
  110. package/js/src/hyperliquid.d.ts +1 -0
  111. package/js/src/hyperliquid.js +14 -4
  112. package/js/src/kraken.d.ts +3 -3
  113. package/js/src/kraken.js +2 -0
  114. package/js/src/krakenfutures.d.ts +2 -2
  115. package/js/src/kucoinfutures.d.ts +5 -5
  116. package/js/src/mexc.d.ts +1 -0
  117. package/js/src/mexc.js +50 -57
  118. package/js/src/okx.js +1 -1
  119. package/js/src/oxfun.d.ts +3 -3
  120. package/js/src/phemex.d.ts +3 -3
  121. package/js/src/phemex.js +2 -1
  122. package/js/src/poloniex.d.ts +3 -3
  123. package/js/src/poloniex.js +2 -1
  124. package/js/src/pro/apex.d.ts +160 -0
  125. package/js/src/pro/apex.js +1038 -0
  126. package/js/src/pro/binance.js +3 -3
  127. package/js/src/pro/coinbase.d.ts +4 -3
  128. package/js/src/pro/coinbase.js +45 -66
  129. package/js/src/pro/gate.js +27 -2
  130. package/js/src/pro/hollaex.js +2 -2
  131. package/js/src/pro/p2b.js +2 -2
  132. package/js/src/pro/tradeogre.d.ts +49 -0
  133. package/js/src/pro/tradeogre.js +278 -0
  134. package/js/src/pro/upbit.d.ts +16 -1
  135. package/js/src/pro/upbit.js +43 -0
  136. package/js/src/probit.js +1 -0
  137. package/js/src/static_dependencies/zklink/zklink-sdk-web.d.ts +1279 -0
  138. package/js/src/static_dependencies/zklink/zklink-sdk-web.js +4276 -0
  139. package/js/src/timex.js +2 -2
  140. package/js/src/tradeogre.js +2 -1
  141. package/js/src/upbit.d.ts +75 -23
  142. package/js/src/upbit.js +277 -67
  143. package/js/src/vertex.d.ts +3 -3
  144. package/js/src/whitebit.js +66 -12
  145. package/js/src/woo.d.ts +4 -4
  146. package/js/src/woo.js +3 -1
  147. package/js/src/woofipro.d.ts +4 -4
  148. package/js/src/xt.d.ts +4 -4
  149. package/js/src/xt.js +9 -0
  150. package/package.json +2 -2
  151. package/js/src/abstract/ace.d.ts +0 -18
  152. package/js/src/ace.d.ts +0 -158
  153. package/js/src/ace.js +0 -1175
  154. /package/js/src/abstract/{ace.js → apex.js} +0 -0
@@ -0,0 +1,1038 @@
1
+ // ---------------------------------------------------------------------------
2
+ import apexRest from '../apex.js';
3
+ import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
4
+ import { ArgumentsRequired, AuthenticationError, ExchangeError } from '../base/errors.js';
5
+ import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
6
+ // ---------------------------------------------------------------------------
7
+ export default class apex extends apexRest {
8
+ describe() {
9
+ return this.deepExtend(super.describe(), {
10
+ 'has': {
11
+ 'ws': true,
12
+ 'watchTicker': true,
13
+ 'watchTickers': true,
14
+ 'watchOrderBook': true,
15
+ 'watchOrders': true,
16
+ 'watchTrades': true,
17
+ 'watchTradesForSymbols': false,
18
+ 'watchPositions': true,
19
+ 'watchMyTrades': true,
20
+ 'watchBalance': false,
21
+ 'watchOHLCV': true,
22
+ },
23
+ 'urls': {
24
+ 'logo': 'https://omni.apex.exchange/assets/logo_content-CY9uyFbz.svg',
25
+ 'api': {
26
+ 'ws': {
27
+ 'public': 'wss://quote.omni.apex.exchange/realtime_public?v=2',
28
+ 'private': 'wss://quote.omni.apex.exchange/realtime_private?v=2',
29
+ },
30
+ },
31
+ 'test': {
32
+ 'ws': {
33
+ 'public': 'wss://qa-quote.omni.apex.exchange/realtime_public?v=2',
34
+ 'private': 'wss://qa-quote.omni.apex.exchange/realtime_private?v=2',
35
+ },
36
+ },
37
+ 'www': 'https://apex.exchange/',
38
+ 'doc': 'https://api-docs.pro.apex.exchange',
39
+ 'fees': 'https://apex-pro.gitbook.io/apex-pro/apex-omni-live-now/trading-perpetual-contracts/trading-fees',
40
+ 'referral': 'https://omni.apex.exchange/trade',
41
+ },
42
+ 'options': {},
43
+ 'streaming': {
44
+ 'ping': this.ping,
45
+ 'keepAlive': 18000,
46
+ },
47
+ });
48
+ }
49
+ /**
50
+ * @method
51
+ * @name apex#watchTrades
52
+ * @description watches information on multiple trades made in a market
53
+ * @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
54
+ * @param {string} symbol unified market symbol of the market trades were made in
55
+ * @param {int} [since] the earliest time in ms to fetch trades for
56
+ * @param {int} [limit] the maximum number of trade structures to retrieve
57
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
58
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
59
+ */
60
+ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
61
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
62
+ }
63
+ /**
64
+ * @method
65
+ * @name apex#watchTradesForSymbols
66
+ * @description get the list of most recent trades for a list of symbols
67
+ * @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
68
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
69
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
70
+ * @param {int} [limit] the maximum amount of trades to fetch
71
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
72
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
73
+ */
74
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
75
+ await this.loadMarkets();
76
+ symbols = this.marketSymbols(symbols);
77
+ const symbolsLength = symbols.length;
78
+ if (symbolsLength === 0) {
79
+ throw new ArgumentsRequired(this.id + ' watchTradesForSymbols() requires a non-empty array of symbols');
80
+ }
81
+ const timeStamp = this.milliseconds().toString();
82
+ const url = this.urls['api']['ws']['public'] + '&timestamp=' + timeStamp;
83
+ const topics = [];
84
+ const messageHashes = [];
85
+ for (let i = 0; i < symbols.length; i++) {
86
+ const symbol = symbols[i];
87
+ const market = this.market(symbol);
88
+ const topic = 'recentlyTrade.H.' + market['id2'];
89
+ topics.push(topic);
90
+ const messageHash = 'trade:' + symbol;
91
+ messageHashes.push(messageHash);
92
+ }
93
+ const trades = await this.watchTopics(url, messageHashes, topics, params);
94
+ if (this.newUpdates) {
95
+ const first = this.safeValue(trades, 0);
96
+ const tradeSymbol = this.safeString(first, 'symbol');
97
+ limit = trades.getLimit(tradeSymbol, limit);
98
+ }
99
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
100
+ }
101
+ handleTrades(client, message) {
102
+ //
103
+ // {
104
+ // "topic": "recentlyTrade.H.BTCUSDT",
105
+ // "type": "snapshot",
106
+ // "ts": 1672304486868,
107
+ // "data": [
108
+ // {
109
+ // "T": 1672304486865,
110
+ // "s": "BTCUSDT",
111
+ // "S": "Buy",
112
+ // "v": "0.001",
113
+ // "p": "16578.50",
114
+ // "L": "PlusTick",
115
+ // "i": "20f43950-d8dd-5b31-9112-a178eb6023af",
116
+ // "BT": false
117
+ // }
118
+ // ]
119
+ // }
120
+ //
121
+ const data = this.safeValue(message, 'data', {});
122
+ const topic = this.safeString(message, 'topic');
123
+ const trades = data;
124
+ const parts = topic.split('.');
125
+ const marketId = this.safeString(parts, 2);
126
+ const market = this.safeMarket(marketId, undefined, undefined);
127
+ const symbol = market['symbol'];
128
+ let stored = this.safeValue(this.trades, symbol);
129
+ if (stored === undefined) {
130
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
131
+ stored = new ArrayCache(limit);
132
+ this.trades[symbol] = stored;
133
+ }
134
+ for (let j = 0; j < trades.length; j++) {
135
+ const parsed = this.parseWsTrade(trades[j], market);
136
+ stored.append(parsed);
137
+ }
138
+ const messageHash = 'trade' + ':' + symbol;
139
+ client.resolve(stored, messageHash);
140
+ }
141
+ parseWsTrade(trade, market = undefined) {
142
+ //
143
+ // public
144
+ // {
145
+ // "T": 1672304486865,
146
+ // "s": "BTCUSDT",
147
+ // "S": "Buy",
148
+ // "v": "0.001",
149
+ // "p": "16578.50",
150
+ // "L": "PlusTick",
151
+ // "i": "20f43950-d8dd-5b31-9112-a178eb6023af",
152
+ // "BT": false
153
+ // }
154
+ //
155
+ const id = this.safeStringN(trade, ['i', 'id', 'v']);
156
+ const marketId = this.safeStringN(trade, ['s', 'symbol']);
157
+ market = this.safeMarket(marketId, market, undefined);
158
+ const symbol = market['symbol'];
159
+ const timestamp = this.safeIntegerN(trade, ['t', 'T', 'createdAt']);
160
+ const side = this.safeStringLowerN(trade, ['S', 'side']);
161
+ const price = this.safeStringN(trade, ['p', 'price']);
162
+ const amount = this.safeStringN(trade, ['q', 'v', 'size']);
163
+ return this.safeTrade({
164
+ 'id': id,
165
+ 'info': trade,
166
+ 'timestamp': timestamp,
167
+ 'datetime': this.iso8601(timestamp),
168
+ 'symbol': symbol,
169
+ 'order': undefined,
170
+ 'type': undefined,
171
+ 'side': side,
172
+ 'takerOrMaker': undefined,
173
+ 'price': price,
174
+ 'amount': amount,
175
+ 'cost': undefined,
176
+ 'fee': undefined,
177
+ }, market);
178
+ }
179
+ /**
180
+ * @method
181
+ * @name apex#watchOrderBook
182
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
183
+ * @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
184
+ * @param {string} symbol unified symbol of the market to fetch the order book for
185
+ * @param {int} [limit] the maximum amount of order book entries to return.
186
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
187
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
188
+ */
189
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
190
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
191
+ }
192
+ /**
193
+ * @method
194
+ * @name apex#watchOrderBookForSymbols
195
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
196
+ * @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
197
+ * @param {string[]} symbols unified array of symbols
198
+ * @param {int} [limit] the maximum amount of order book entries to return.
199
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
200
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
201
+ */
202
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
203
+ await this.loadMarkets();
204
+ const symbolsLength = symbols.length;
205
+ if (symbolsLength === 0) {
206
+ throw new ArgumentsRequired(this.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols');
207
+ }
208
+ symbols = this.marketSymbols(symbols);
209
+ const timeStamp = this.milliseconds().toString();
210
+ const url = this.urls['api']['ws']['public'] + '&timestamp=' + timeStamp;
211
+ const topics = [];
212
+ const messageHashes = [];
213
+ for (let i = 0; i < symbols.length; i++) {
214
+ const symbol = symbols[i];
215
+ const market = this.market(symbol);
216
+ if (limit === undefined) {
217
+ limit = 25;
218
+ }
219
+ const topic = 'orderBook' + limit.toString() + '.H.' + market['id2'];
220
+ topics.push(topic);
221
+ const messageHash = 'orderbook:' + symbol;
222
+ messageHashes.push(messageHash);
223
+ }
224
+ const orderbook = await this.watchTopics(url, messageHashes, topics, params);
225
+ return orderbook.limit();
226
+ }
227
+ async watchTopics(url, messageHashes, topics, params = {}) {
228
+ const request = {
229
+ 'op': 'subscribe',
230
+ 'args': topics,
231
+ };
232
+ const message = this.extend(request, params);
233
+ return await this.watchMultiple(url, messageHashes, message, messageHashes);
234
+ }
235
+ handleOrderBook(client, message) {
236
+ //
237
+ // {
238
+ // "topic": "orderbook25.H.BTCUSDT",
239
+ // "type": "snapshot",
240
+ // "ts": 1672304484978,
241
+ // "data": {
242
+ // "s": "BTCUSDT",
243
+ // "b": [
244
+ // ...,
245
+ // [
246
+ // "16493.50",
247
+ // "0.006"
248
+ // ],
249
+ // [
250
+ // "16493.00",
251
+ // "0.100"
252
+ // ]
253
+ // ],
254
+ // "a": [
255
+ // [
256
+ // "16611.00",
257
+ // "0.029"
258
+ // ],
259
+ // [
260
+ // "16612.00",
261
+ // "0.213"
262
+ // ],
263
+ // ],
264
+ // "u": 18521288,
265
+ // "seq": 7961638724
266
+ // }
267
+ // }
268
+ //
269
+ const type = this.safeString(message, 'type');
270
+ const isSnapshot = (type === 'snapshot');
271
+ const data = this.safeDict(message, 'data', {});
272
+ const marketId = this.safeString(data, 's');
273
+ const market = this.safeMarket(marketId, undefined, undefined);
274
+ const symbol = market['symbol'];
275
+ const timestamp = this.safeIntegerProduct(message, 'ts', 0.001);
276
+ if (!(symbol in this.orderbooks)) {
277
+ this.orderbooks[symbol] = this.orderBook();
278
+ }
279
+ const orderbook = this.orderbooks[symbol];
280
+ if (isSnapshot) {
281
+ const snapshot = this.parseOrderBook(data, symbol, timestamp, 'b', 'a');
282
+ orderbook.reset(snapshot);
283
+ }
284
+ else {
285
+ const asks = this.safeList(data, 'a', []);
286
+ const bids = this.safeList(data, 'b', []);
287
+ this.handleDeltas(orderbook['asks'], asks);
288
+ this.handleDeltas(orderbook['bids'], bids);
289
+ orderbook['timestamp'] = timestamp;
290
+ orderbook['datetime'] = this.iso8601(timestamp);
291
+ }
292
+ const messageHash = 'orderbook' + ':' + symbol;
293
+ this.orderbooks[symbol] = orderbook;
294
+ client.resolve(orderbook, messageHash);
295
+ }
296
+ handleDelta(bookside, delta) {
297
+ const bidAsk = this.parseBidAsk(delta, 0, 1);
298
+ bookside.storeArray(bidAsk);
299
+ }
300
+ handleDeltas(bookside, deltas) {
301
+ for (let i = 0; i < deltas.length; i++) {
302
+ this.handleDelta(bookside, deltas[i]);
303
+ }
304
+ }
305
+ /**
306
+ * @method
307
+ * @name apex#watchTicker
308
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
309
+ * @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
310
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
311
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
312
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
313
+ */
314
+ async watchTicker(symbol, params = {}) {
315
+ await this.loadMarkets();
316
+ const market = this.market(symbol);
317
+ symbol = market['symbol'];
318
+ const timeStamp = this.milliseconds().toString();
319
+ const url = this.urls['api']['ws']['public'] + '&timestamp=' + timeStamp;
320
+ const messageHash = 'ticker:' + symbol;
321
+ const topic = 'instrumentInfo' + '.H.' + market['id2'];
322
+ const topics = [topic];
323
+ return await this.watchTopics(url, [messageHash], topics, params);
324
+ }
325
+ /**
326
+ * @method
327
+ * @name apex#watchTickers
328
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
329
+ * @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
330
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
331
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
332
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
333
+ */
334
+ async watchTickers(symbols = undefined, params = {}) {
335
+ await this.loadMarkets();
336
+ symbols = this.marketSymbols(symbols, undefined, false);
337
+ const messageHashes = [];
338
+ const timeStamp = this.milliseconds().toString();
339
+ const url = this.urls['api']['ws']['public'] + '&timestamp=' + timeStamp;
340
+ const topics = [];
341
+ for (let i = 0; i < symbols.length; i++) {
342
+ const symbol = symbols[i];
343
+ const market = this.market(symbol);
344
+ const topic = 'instrumentInfo' + '.H.' + market['id2'];
345
+ topics.push(topic);
346
+ const messageHash = 'ticker:' + symbol;
347
+ messageHashes.push(messageHash);
348
+ }
349
+ const ticker = await this.watchTopics(url, messageHashes, topics, params);
350
+ if (this.newUpdates) {
351
+ const result = {};
352
+ result[ticker['symbol']] = ticker;
353
+ return result;
354
+ }
355
+ return this.filterByArray(this.tickers, 'symbol', symbols);
356
+ }
357
+ handleTicker(client, message) {
358
+ // "topic":"instrumentInfo.H.BTCUSDT",
359
+ // "type":"snapshot",
360
+ // "data":{
361
+ // "symbol":"BTCUSDT",
362
+ // "lastPrice":"21572.5",
363
+ // "price24hPcnt":"-0.0194318181818182",
364
+ // "highPrice24h":"25306.5",
365
+ // "lowPrice24h":"17001.5",
366
+ // "turnover24h":"1334891.4545",
367
+ // "volume24h":"64.896",
368
+ // "nextFundingTime":"2022-08-26T08:00:00Z",
369
+ // "oraclePrice":"21412.060000000002752512",
370
+ // "indexPrice":"21409.82",
371
+ // "openInterest":"49.598",
372
+ // "tradeCount":"0",
373
+ // "fundingRate":"0.0000125",
374
+ // "predictedFundingRate":"0.0000125"
375
+ // },
376
+ // "cs":44939063,
377
+ // "ts":1661500091955487
378
+ // }
379
+ const topic = this.safeString(message, 'topic', '');
380
+ const updateType = this.safeString(message, 'type', '');
381
+ const data = this.safeDict(message, 'data', {});
382
+ let symbol = undefined;
383
+ let parsed = undefined;
384
+ if ((updateType === 'snapshot')) {
385
+ parsed = this.parseTicker(data);
386
+ symbol = parsed['symbol'];
387
+ }
388
+ else if (updateType === 'delta') {
389
+ const topicParts = topic.split('.');
390
+ const topicLength = topicParts.length;
391
+ const marketId = this.safeString(topicParts, topicLength - 1);
392
+ const market = this.safeMarket(marketId, undefined, undefined);
393
+ symbol = market['symbol'];
394
+ const ticker = this.safeDict(this.tickers, symbol, {});
395
+ const rawTicker = this.safeDict(ticker, 'info', {});
396
+ const merged = this.extend(rawTicker, data);
397
+ parsed = this.parseTicker(merged);
398
+ }
399
+ const timestamp = this.safeIntegerProduct(message, 'ts', 0.001);
400
+ parsed['timestamp'] = timestamp;
401
+ parsed['datetime'] = this.iso8601(timestamp);
402
+ this.tickers[symbol] = parsed;
403
+ const messageHash = 'ticker:' + symbol;
404
+ client.resolve(this.tickers[symbol], messageHash);
405
+ }
406
+ /**
407
+ * @method
408
+ * @name apex#watchOHLCV
409
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
410
+ * @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
411
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
412
+ * @param {string} timeframe the length of time each candle represents
413
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
414
+ * @param {int} [limit] the maximum amount of candles to fetch
415
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
416
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
417
+ */
418
+ async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
419
+ params['callerMethodName'] = 'watchOHLCV';
420
+ const result = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, params);
421
+ return result[symbol][timeframe];
422
+ }
423
+ /**
424
+ * @method
425
+ * @name apex#watchOHLCVForSymbols
426
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
427
+ * @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
428
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
429
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
430
+ * @param {int} [limit] the maximum amount of candles to fetch
431
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
432
+ * @returns {object} A list of candles ordered as timestamp, open, high, low, close, volume
433
+ */
434
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
435
+ await this.loadMarkets();
436
+ const timeStamp = this.milliseconds().toString();
437
+ const url = this.urls['api']['ws']['public'] + '&timestamp=' + timeStamp;
438
+ const rawHashes = [];
439
+ const messageHashes = [];
440
+ for (let i = 0; i < symbolsAndTimeframes.length; i++) {
441
+ const data = symbolsAndTimeframes[i];
442
+ let symbolString = this.safeString(data, 0);
443
+ const market = this.market(symbolString);
444
+ symbolString = market['id2'];
445
+ const unfiedTimeframe = this.safeString(data, 1, '1');
446
+ const timeframeId = this.safeString(this.timeframes, unfiedTimeframe, unfiedTimeframe);
447
+ rawHashes.push('candle.' + timeframeId + '.' + symbolString);
448
+ messageHashes.push('ohlcv::' + symbolString + '::' + unfiedTimeframe);
449
+ }
450
+ const [symbol, timeframe, stored] = await this.watchTopics(url, messageHashes, rawHashes, params);
451
+ if (this.newUpdates) {
452
+ limit = stored.getLimit(symbol, limit);
453
+ }
454
+ const filtered = this.filterBySinceLimit(stored, since, limit, 0, true);
455
+ return this.createOHLCVObject(symbol, timeframe, filtered);
456
+ }
457
+ handleOHLCV(client, message) {
458
+ //
459
+ // {
460
+ // "topic": "candle.5.BTCUSDT",
461
+ // "data": [
462
+ // {
463
+ // "start": 1672324800000,
464
+ // "end": 1672325099999,
465
+ // "interval": "5",
466
+ // "open": "16649.5",
467
+ // "close": "16677",
468
+ // "high": "16677",
469
+ // "low": "16608",
470
+ // "volume": "2.081",
471
+ // "turnover": "34666.4005",
472
+ // "confirm": false,
473
+ // "timestamp": 1672324988882
474
+ // }
475
+ // ],
476
+ // "ts": 1672324988882,
477
+ // "type": "snapshot"
478
+ // }
479
+ //
480
+ const data = this.safeValue(message, 'data', {});
481
+ const topic = this.safeString(message, 'topic');
482
+ const topicParts = topic.split('.');
483
+ const topicLength = topicParts.length;
484
+ const timeframeId = this.safeString(topicParts, 1);
485
+ const timeframe = this.findTimeframe(timeframeId);
486
+ const marketId = this.safeString(topicParts, topicLength - 1);
487
+ const isSpot = client.url.indexOf('spot') > -1;
488
+ const marketType = isSpot ? 'spot' : 'contract';
489
+ const market = this.safeMarket(marketId, undefined, undefined, marketType);
490
+ const symbol = market['symbol'];
491
+ const ohlcvsByTimeframe = this.safeValue(this.ohlcvs, symbol);
492
+ if (ohlcvsByTimeframe === undefined) {
493
+ this.ohlcvs[symbol] = {};
494
+ }
495
+ if (this.safeValue(ohlcvsByTimeframe, timeframe) === undefined) {
496
+ const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
497
+ this.ohlcvs[symbol][timeframe] = new ArrayCacheByTimestamp(limit);
498
+ }
499
+ const stored = this.ohlcvs[symbol][timeframe];
500
+ for (let i = 0; i < data.length; i++) {
501
+ const parsed = this.parseWsOHLCV(data[i]);
502
+ stored.append(parsed);
503
+ }
504
+ const messageHash = 'ohlcv::' + symbol + '::' + timeframe;
505
+ const resolveData = [symbol, timeframe, stored];
506
+ client.resolve(resolveData, messageHash);
507
+ }
508
+ parseWsOHLCV(ohlcv, market = undefined) {
509
+ //
510
+ // {
511
+ // "start": 1670363160000,
512
+ // "end": 1670363219999,
513
+ // "interval": "1",
514
+ // "open": "16987.5",
515
+ // "close": "16987.5",
516
+ // "high": "16988",
517
+ // "low": "16987.5",
518
+ // "volume": "23.511",
519
+ // "turnover": "399396.344",
520
+ // "confirm": false,
521
+ // "timestamp": 1670363219614
522
+ // }
523
+ //
524
+ return [
525
+ this.safeInteger(ohlcv, 'start'),
526
+ this.safeNumber(ohlcv, 'open'),
527
+ this.safeNumber(ohlcv, 'high'),
528
+ this.safeNumber(ohlcv, 'low'),
529
+ this.safeNumber(ohlcv, 'close'),
530
+ this.safeNumber2(ohlcv, 'volume', 'turnover'),
531
+ ];
532
+ }
533
+ /**
534
+ * @method
535
+ * @name apex#watchMyTrades
536
+ * @description watches information on multiple trades made by the user
537
+ * @see https://api-docs.pro.apex.exchange/#private-websocket
538
+ * @param {string} symbol unified market symbol of the market orders were made in
539
+ * @param {int} [since] the earliest time in ms to fetch orders for
540
+ * @param {int} [limit] the maximum number of order structures to retrieve
541
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
542
+ * @param {boolean} [params.unifiedMargin] use unified margin account
543
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
544
+ */
545
+ async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
546
+ let messageHash = 'myTrades';
547
+ await this.loadMarkets();
548
+ if (symbol !== undefined) {
549
+ symbol = this.symbol(symbol);
550
+ messageHash += ':' + symbol;
551
+ }
552
+ const timeStamp = this.milliseconds().toString();
553
+ const url = this.urls['api']['ws']['private'] + '&timestamp=' + timeStamp;
554
+ await this.authenticate(url);
555
+ const trades = await this.watchTopics(url, [messageHash], ['myTrades'], params);
556
+ if (this.newUpdates) {
557
+ limit = trades.getLimit(symbol, limit);
558
+ }
559
+ return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
560
+ }
561
+ /**
562
+ * @method
563
+ * @name apex#watchPositions
564
+ * @see https://api-docs.pro.apex.exchange/#private-websocket
565
+ * @description watch all open positions
566
+ * @param {string[]} [symbols] list of unified market symbols
567
+ * @param {int} [since] the earliest time in ms to fetch positions for
568
+ * @param {int} [limit] the maximum number of positions to retrieve
569
+ * @param {object} params extra parameters specific to the exchange API endpoint
570
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
571
+ */
572
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
573
+ await this.loadMarkets();
574
+ let messageHash = '';
575
+ if (!this.isEmpty(symbols)) {
576
+ symbols = this.marketSymbols(symbols);
577
+ messageHash = '::' + symbols.join(',');
578
+ }
579
+ const timeStamp = this.milliseconds().toString();
580
+ const url = this.urls['api']['ws']['private'] + '&timestamp=' + timeStamp;
581
+ messageHash = 'positions' + messageHash;
582
+ const client = this.client(url);
583
+ await this.authenticate(url);
584
+ this.setPositionsCache(client, symbols);
585
+ const cache = this.positions;
586
+ if (cache === undefined) {
587
+ const snapshot = await client.future('fetchPositionsSnapshot');
588
+ return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
589
+ }
590
+ const topics = ['positions'];
591
+ const newPositions = await this.watchTopics(url, [messageHash], topics, params);
592
+ if (this.newUpdates) {
593
+ return newPositions;
594
+ }
595
+ return this.filterBySymbolsSinceLimit(cache, symbols, since, limit, true);
596
+ }
597
+ /**
598
+ * @method
599
+ * @name apex#watchOrders
600
+ * @description watches information on multiple orders made by the user
601
+ * @see https://api-docs.pro.apex.exchange/#private-websocket
602
+ * @param {string} symbol unified market symbol of the market orders were made in
603
+ * @param {int} [since] the earliest time in ms to fetch orders for
604
+ * @param {int} [limit] the maximum number of order structures to retrieve
605
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
606
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
607
+ */
608
+ async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
609
+ await this.loadMarkets();
610
+ let messageHash = 'orders';
611
+ if (symbol !== undefined) {
612
+ symbol = this.symbol(symbol);
613
+ messageHash += ':' + symbol;
614
+ }
615
+ const timeStamp = this.milliseconds().toString();
616
+ const url = this.urls['api']['ws']['private'] + '&timestamp=' + timeStamp;
617
+ await this.authenticate(url);
618
+ const topics = ['orders'];
619
+ const orders = await this.watchTopics(url, [messageHash], topics, params);
620
+ if (this.newUpdates) {
621
+ limit = orders.getLimit(symbol, limit);
622
+ }
623
+ return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
624
+ }
625
+ handleMyTrades(client, lists) {
626
+ // [
627
+ // {
628
+ // "symbol":"ETH-USDT",
629
+ // "side":"BUY",
630
+ // "orderId":"2048046080",
631
+ // "fee":"0.625000",
632
+ // "liquidity":"TAKER",
633
+ // "accountId":"1024000",
634
+ // "createdAt":1652185521361,
635
+ // "isOpen":true,
636
+ // "size":"0.500",
637
+ // "price":"2500.0",
638
+ // "quoteAmount":"1250.0000",
639
+ // "id":"2048000182272",
640
+ // "updatedAt":1652185678345
641
+ // }
642
+ // ]
643
+ if (this.myTrades === undefined) {
644
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
645
+ this.myTrades = new ArrayCacheBySymbolById(limit);
646
+ }
647
+ const trades = this.myTrades;
648
+ const symbols = {};
649
+ for (let i = 0; i < lists.length; i++) {
650
+ const rawTrade = lists[i];
651
+ let parsed = undefined;
652
+ parsed = this.parseWsTrade(rawTrade);
653
+ const symbol = parsed['symbol'];
654
+ symbols[symbol] = true;
655
+ trades.append(parsed);
656
+ }
657
+ const keys = Object.keys(symbols);
658
+ for (let i = 0; i < keys.length; i++) {
659
+ const currentMessageHash = 'myTrades:' + keys[i];
660
+ client.resolve(trades, currentMessageHash);
661
+ }
662
+ // non-symbol specific
663
+ const messageHash = 'myTrades';
664
+ client.resolve(trades, messageHash);
665
+ }
666
+ handleOrder(client, lists) {
667
+ // [
668
+ // {
669
+ // "symbol":"ETH-USDT",
670
+ // "cumSuccessFillFee":"0.625000",
671
+ // "trailingPercent":"0",
672
+ // "type":"LIMIT",
673
+ // "unfillableAt":1654779600000,
674
+ // "isDeleverage":false,
675
+ // "createdAt":1652185521339,
676
+ // "price":"2500.0",
677
+ // "cumSuccessFillValue":"0",
678
+ // "id":"2048046080",
679
+ // "cancelReason":"",
680
+ // "timeInForce":1,
681
+ // "updatedAt":1652185521392,
682
+ // "limitFee":"0.625000",
683
+ // "side":"BUY",
684
+ // "clientOrderId":"522843990",
685
+ // "triggerPrice":"",
686
+ // "expiresAt":1654779600000,
687
+ // "cumSuccessFillSize":"0",
688
+ // "accountId":"1024000",
689
+ // "size":"0.500",
690
+ // "reduceOnly":false,
691
+ // "isLiquidate":false,
692
+ // "remainingSize":"0.000",
693
+ // "status":"PENDING"
694
+ // }
695
+ // ]
696
+ if (this.orders === undefined) {
697
+ const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
698
+ this.orders = new ArrayCacheBySymbolById(limit);
699
+ }
700
+ const orders = this.orders;
701
+ const symbols = {};
702
+ for (let i = 0; i < lists.length; i++) {
703
+ let parsed = undefined;
704
+ parsed = this.parseOrder(lists[i]);
705
+ const symbol = parsed['symbol'];
706
+ symbols[symbol] = true;
707
+ orders.append(parsed);
708
+ }
709
+ const symbolsArray = Object.keys(symbols);
710
+ for (let i = 0; i < symbolsArray.length; i++) {
711
+ const currentMessageHash = 'orders:' + symbolsArray[i];
712
+ client.resolve(orders, currentMessageHash);
713
+ }
714
+ const messageHash = 'orders';
715
+ client.resolve(orders, messageHash);
716
+ }
717
+ setPositionsCache(client, symbols = undefined) {
718
+ if (this.positions !== undefined) {
719
+ return;
720
+ }
721
+ const messageHash = 'fetchPositionsSnapshot';
722
+ if (!(messageHash in client.futures)) {
723
+ client.future(messageHash);
724
+ this.spawn(this.loadPositionsSnapshot, client, messageHash);
725
+ }
726
+ }
727
+ async loadPositionsSnapshot(client, messageHash) {
728
+ // as only one ws channel gives positions for all types, for snapshot must load all positions
729
+ const fetchFunctions = [
730
+ this.fetchPositions(undefined),
731
+ ];
732
+ const promises = await Promise.all(fetchFunctions);
733
+ this.positions = new ArrayCacheBySymbolBySide();
734
+ const cache = this.positions;
735
+ for (let i = 0; i < promises.length; i++) {
736
+ const positions = promises[i];
737
+ for (let ii = 0; ii < positions.length; ii++) {
738
+ const position = positions[ii];
739
+ cache.append(position);
740
+ }
741
+ }
742
+ // don't remove the future from the .futures cache
743
+ const future = client.futures[messageHash];
744
+ future.resolve(cache);
745
+ client.resolve(cache, 'positions');
746
+ }
747
+ handlePositions(client, lists) {
748
+ //
749
+ // [
750
+ // {
751
+ // "symbol":"ETH-USDT",
752
+ // "exitPrice":"0",
753
+ // "side":"LONG",
754
+ // "maxSize":"2820.000",
755
+ // "sumOpen":"1.820",
756
+ // "sumClose":"0.000",
757
+ // "netFunding":"0.000000",
758
+ // "entryPrice":"2500.000000000000000000",
759
+ // "accountId":"1024000",
760
+ // "createdAt":1652179377769,
761
+ // "size":"1.820",
762
+ // "realizedPnl":"0",
763
+ // "closedAt":1652185521392,
764
+ // "updatedAt":1652185521392
765
+ // }
766
+ // ]
767
+ //
768
+ // each account is connected to a different endpoint
769
+ // and has exactly one subscriptionhash which is the account type
770
+ if (this.positions === undefined) {
771
+ this.positions = new ArrayCacheBySymbolBySide();
772
+ }
773
+ const cache = this.positions;
774
+ const newPositions = [];
775
+ for (let i = 0; i < lists.length; i++) {
776
+ const rawPosition = lists[i];
777
+ const position = this.parsePosition(rawPosition);
778
+ const side = this.safeString(position, 'side');
779
+ // hacky solution to handle closing positions
780
+ // without crashing, we should handle this properly later
781
+ newPositions.push(position);
782
+ if (side === undefined || side === '') {
783
+ // closing update, adding both sides to "reset" both sides
784
+ // since we don't know which side is being closed
785
+ position['side'] = 'long';
786
+ cache.append(position);
787
+ position['side'] = 'short';
788
+ cache.append(position);
789
+ position['side'] = undefined;
790
+ }
791
+ else {
792
+ // regular update
793
+ cache.append(position);
794
+ }
795
+ }
796
+ const messageHashes = this.findMessageHashes(client, 'positions::');
797
+ for (let i = 0; i < messageHashes.length; i++) {
798
+ const messageHash = messageHashes[i];
799
+ const parts = messageHash.split('::');
800
+ const symbolsString = parts[1];
801
+ const symbols = symbolsString.split(',');
802
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
803
+ if (!this.isEmpty(positions)) {
804
+ client.resolve(positions, messageHash);
805
+ }
806
+ }
807
+ client.resolve(newPositions, 'positions');
808
+ }
809
+ async authenticate(url, params = {}) {
810
+ this.checkRequiredCredentials();
811
+ const timestamp = this.milliseconds().toString();
812
+ const request_path = '/ws/accounts';
813
+ const http_method = 'GET';
814
+ const messageString = (timestamp + http_method + request_path);
815
+ const signature = this.hmac(this.encode(messageString), this.encode(this.stringToBase64(this.secret)), sha256, 'base64');
816
+ const messageHash = 'authenticated';
817
+ const client = this.client(url);
818
+ const future = client.future(messageHash);
819
+ const authenticated = this.safeValue(client.subscriptions, messageHash);
820
+ if (authenticated === undefined) {
821
+ // auth sign
822
+ const request = {
823
+ 'type': 'login',
824
+ 'topics': ['ws_zk_accounts_v3'],
825
+ 'httpMethod': http_method,
826
+ 'requestPath': request_path,
827
+ 'apiKey': this.apiKey,
828
+ 'passphrase': this.password,
829
+ 'timestamp': timestamp,
830
+ 'signature': signature,
831
+ };
832
+ const message = {
833
+ 'op': 'login',
834
+ 'args': [JSON.stringify(request)],
835
+ };
836
+ this.watch(url, messageHash, message, messageHash);
837
+ }
838
+ return await future;
839
+ }
840
+ handleErrorMessage(client, message) {
841
+ //
842
+ // {
843
+ // "success": false,
844
+ // "ret_msg": "error:invalid op",
845
+ // "conn_id": "5e079fdd-9c7f-404d-9dbf-969d650838b5",
846
+ // "request": { op: '', args: null }
847
+ // }
848
+ //
849
+ // auth error
850
+ //
851
+ // {
852
+ // "success": false,
853
+ // "ret_msg": "error:USVC1111",
854
+ // "conn_id": "e73770fb-a0dc-45bd-8028-140e20958090",
855
+ // "request": {
856
+ // "op": "auth",
857
+ // "args": [
858
+ // "9rFT6uR4uz9Imkw4Wx",
859
+ // "1653405853543",
860
+ // "542e71bd85597b4db0290f0ce2d13ed1fd4bb5df3188716c1e9cc69a879f7889"
861
+ // ]
862
+ // }
863
+ //
864
+ // { code: '-10009', desc: "Invalid period!" }
865
+ //
866
+ // {
867
+ // "reqId":"1",
868
+ // "retCode":170131,
869
+ // "retMsg":"Insufficient balance.",
870
+ // "op":"order.create",
871
+ // "data":{
872
+ //
873
+ // },
874
+ // "header":{
875
+ // "X-Bapi-Limit":"20",
876
+ // "X-Bapi-Limit-Status":"19",
877
+ // "X-Bapi-Limit-Reset-Timestamp":"1714236608944",
878
+ // "Traceid":"3d7168a137bf32a947b7e5e6a575ac7f",
879
+ // "Timenow":"1714236608946"
880
+ // },
881
+ // "connId":"cojifin88smerbj9t560-406"
882
+ // }
883
+ //
884
+ const code = this.safeStringN(message, ['code', 'ret_code', 'retCode']);
885
+ try {
886
+ if (code !== undefined && code !== '0') {
887
+ const feedback = this.id + ' ' + this.json(message);
888
+ this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
889
+ const msg = this.safeString2(message, 'retMsg', 'ret_msg');
890
+ this.throwBroadlyMatchedException(this.exceptions['broad'], msg, feedback);
891
+ throw new ExchangeError(feedback);
892
+ }
893
+ const success = this.safeValue(message, 'success');
894
+ if (success !== undefined && !success) {
895
+ const ret_msg = this.safeString(message, 'ret_msg');
896
+ const request = this.safeValue(message, 'request', {});
897
+ const op = this.safeString(request, 'op');
898
+ if (op === 'auth') {
899
+ throw new AuthenticationError('Authentication failed: ' + ret_msg);
900
+ }
901
+ else {
902
+ throw new ExchangeError(this.id + ' ' + ret_msg);
903
+ }
904
+ }
905
+ return false;
906
+ }
907
+ catch (error) {
908
+ if (error instanceof AuthenticationError) {
909
+ const messageHash = 'authenticated';
910
+ client.reject(error, messageHash);
911
+ if (messageHash in client.subscriptions) {
912
+ delete client.subscriptions[messageHash];
913
+ }
914
+ }
915
+ else {
916
+ const messageHash = this.safeString(message, 'reqId');
917
+ client.reject(error, messageHash);
918
+ }
919
+ return true;
920
+ }
921
+ }
922
+ handleMessage(client, message) {
923
+ if (this.handleErrorMessage(client, message)) {
924
+ return;
925
+ }
926
+ const topic = this.safeString2(message, 'topic', 'op', '');
927
+ const methods = {
928
+ 'ws_zk_accounts_v3': this.handleAccount,
929
+ 'orderBook': this.handleOrderBook,
930
+ 'depth': this.handleOrderBook,
931
+ 'candle': this.handleOHLCV,
932
+ 'kline': this.handleOHLCV,
933
+ 'ticker': this.handleTicker,
934
+ 'instrumentInfo': this.handleTicker,
935
+ 'trade': this.handleTrades,
936
+ 'recentlyTrade': this.handleTrades,
937
+ 'pong': this.handlePong,
938
+ 'auth': this.handleAuthenticate,
939
+ };
940
+ const exacMethod = this.safeValue(methods, topic);
941
+ if (exacMethod !== undefined) {
942
+ exacMethod.call(this, client, message);
943
+ return;
944
+ }
945
+ const keys = Object.keys(methods);
946
+ for (let i = 0; i < keys.length; i++) {
947
+ const key = keys[i];
948
+ if (topic.indexOf(keys[i]) >= 0) {
949
+ const method = methods[key];
950
+ method.call(this, client, message);
951
+ return;
952
+ }
953
+ }
954
+ // unified auth acknowledgement
955
+ const type = this.safeString(message, 'type');
956
+ if (type === 'AUTH_RESP') {
957
+ this.handleAuthenticate(client, message);
958
+ }
959
+ }
960
+ ping(client) {
961
+ const timeStamp = this.milliseconds().toString();
962
+ return {
963
+ 'args': [timeStamp],
964
+ 'op': 'ping',
965
+ };
966
+ }
967
+ handlePong(client, message) {
968
+ //
969
+ // {
970
+ // "success": true,
971
+ // "ret_msg": "pong",
972
+ // "conn_id": "db3158a0-8960-44b9-a9de-ac350ee13158",
973
+ // "request": { op: "ping", args: null }
974
+ // }
975
+ //
976
+ // { pong: 1653296711335 }
977
+ //
978
+ client.lastPong = this.safeInteger(message, 'pong');
979
+ return message;
980
+ }
981
+ handleAccount(client, message) {
982
+ const contents = this.safeDict(message, 'contents', {});
983
+ const fills = this.safeList(contents, 'fills', []);
984
+ if (fills !== undefined) {
985
+ this.handleMyTrades(client, fills);
986
+ }
987
+ const positions = this.safeList(contents, 'positions', []);
988
+ if (positions !== undefined) {
989
+ this.handlePositions(client, positions);
990
+ }
991
+ const orders = this.safeList(contents, 'orders', []);
992
+ if (orders !== undefined) {
993
+ this.handleOrder(client, orders);
994
+ }
995
+ }
996
+ handleAuthenticate(client, message) {
997
+ //
998
+ // {
999
+ // "success": true,
1000
+ // "ret_msg": '',
1001
+ // "op": "auth",
1002
+ // "conn_id": "ce3dpomvha7dha97tvp0-2xh"
1003
+ // }
1004
+ //
1005
+ const success = this.safeValue(message, 'success');
1006
+ const code = this.safeInteger(message, 'retCode');
1007
+ const messageHash = 'authenticated';
1008
+ if (success || code === 0) {
1009
+ const future = this.safeValue(client.futures, messageHash);
1010
+ future.resolve(true);
1011
+ }
1012
+ else {
1013
+ const error = new AuthenticationError(this.id + ' ' + this.json(message));
1014
+ client.reject(error, messageHash);
1015
+ if (messageHash in client.subscriptions) {
1016
+ delete client.subscriptions[messageHash];
1017
+ }
1018
+ }
1019
+ return message;
1020
+ }
1021
+ handleSubscriptionStatus(client, message) {
1022
+ //
1023
+ // {
1024
+ // "topic": "kline",
1025
+ // "event": "sub",
1026
+ // "params": {
1027
+ // "symbol": "LTCUSDT",
1028
+ // "binary": "false",
1029
+ // "klineType": "1m",
1030
+ // "symbolName": "LTCUSDT"
1031
+ // },
1032
+ // "code": "0",
1033
+ // "msg": "Success"
1034
+ // }
1035
+ //
1036
+ return message;
1037
+ }
1038
+ }