ccxt 4.4.77__py2.py3-none-any.whl → 4.4.80__py2.py3-none-any.whl

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