ccxt 4.3.33__py2.py3-none-any.whl → 4.3.34__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 (200) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/binance.py +1 -0
  3. ccxt/abstract/binancecoinm.py +1 -0
  4. ccxt/abstract/binanceus.py +1 -0
  5. ccxt/abstract/binanceusdm.py +1 -0
  6. ccxt/ace.py +2 -2
  7. ccxt/alpaca.py +1 -1
  8. ccxt/ascendex.py +2 -2
  9. ccxt/async_support/__init__.py +1 -1
  10. ccxt/async_support/ace.py +2 -2
  11. ccxt/async_support/alpaca.py +1 -1
  12. ccxt/async_support/ascendex.py +2 -2
  13. ccxt/async_support/base/exchange.py +17 -1
  14. ccxt/async_support/bigone.py +2 -2
  15. ccxt/async_support/binance.py +4 -3
  16. ccxt/async_support/bingx.py +2 -2
  17. ccxt/async_support/bit2c.py +1 -1
  18. ccxt/async_support/bitbank.py +1 -1
  19. ccxt/async_support/bitbns.py +1 -1
  20. ccxt/async_support/bitfinex.py +2 -2
  21. ccxt/async_support/bitfinex2.py +1 -1
  22. ccxt/async_support/bitflyer.py +1 -1
  23. ccxt/async_support/bitget.py +3 -3
  24. ccxt/async_support/bithumb.py +1 -1
  25. ccxt/async_support/bitmart.py +2 -2
  26. ccxt/async_support/bitmex.py +3 -3
  27. ccxt/async_support/bitopro.py +3 -3
  28. ccxt/async_support/bitrue.py +2 -2
  29. ccxt/async_support/bitso.py +2 -2
  30. ccxt/async_support/bitstamp.py +2 -2
  31. ccxt/async_support/bitteam.py +3 -3
  32. ccxt/async_support/bitvavo.py +2 -2
  33. ccxt/async_support/blockchaincom.py +1 -1
  34. ccxt/async_support/blofin.py +3 -3
  35. ccxt/async_support/btcalpha.py +3 -3
  36. ccxt/async_support/btcbox.py +1 -1
  37. ccxt/async_support/btcmarkets.py +3 -3
  38. ccxt/async_support/btcturk.py +1 -1
  39. ccxt/async_support/bybit.py +2 -2
  40. ccxt/async_support/cex.py +1 -1
  41. ccxt/async_support/coinbase.py +96 -55
  42. ccxt/async_support/coinbaseexchange.py +1 -1
  43. ccxt/async_support/coinbaseinternational.py +3 -3
  44. ccxt/async_support/coincheck.py +2 -2
  45. ccxt/async_support/coinex.py +2 -2
  46. ccxt/async_support/coinlist.py +2 -2
  47. ccxt/async_support/coinmate.py +2 -2
  48. ccxt/async_support/coinmetro.py +2 -2
  49. ccxt/async_support/coinone.py +1 -1
  50. ccxt/async_support/coinsph.py +2 -2
  51. ccxt/async_support/cryptocom.py +1 -1
  52. ccxt/async_support/currencycom.py +2 -2
  53. ccxt/async_support/delta.py +1 -1
  54. ccxt/async_support/deribit.py +2 -2
  55. ccxt/async_support/digifinex.py +2 -2
  56. ccxt/async_support/exmo.py +2 -2
  57. ccxt/async_support/gate.py +2 -2
  58. ccxt/async_support/gemini.py +2 -2
  59. ccxt/async_support/hitbtc.py +2 -2
  60. ccxt/async_support/hollaex.py +1 -1
  61. ccxt/async_support/htx.py +2 -2
  62. ccxt/async_support/huobijp.py +2 -2
  63. ccxt/async_support/hyperliquid.py +2 -2
  64. ccxt/async_support/idex.py +2 -2
  65. ccxt/async_support/indodax.py +2 -2
  66. ccxt/async_support/kraken.py +2 -2
  67. ccxt/async_support/krakenfutures.py +1 -1
  68. ccxt/async_support/kucoin.py +2 -2
  69. ccxt/async_support/kuna.py +2 -2
  70. ccxt/async_support/latoken.py +2 -2
  71. ccxt/async_support/lbank.py +1 -1
  72. ccxt/async_support/luno.py +1 -1
  73. ccxt/async_support/lykke.py +1 -1
  74. ccxt/async_support/mercado.py +1 -1
  75. ccxt/async_support/mexc.py +1 -1
  76. ccxt/async_support/ndax.py +2 -2
  77. ccxt/async_support/novadax.py +3 -3
  78. ccxt/async_support/oceanex.py +2 -2
  79. ccxt/async_support/okcoin.py +3 -3
  80. ccxt/async_support/okx.py +3 -3
  81. ccxt/async_support/onetrading.py +2 -2
  82. ccxt/async_support/p2b.py +2 -2
  83. ccxt/async_support/paymium.py +1 -1
  84. ccxt/async_support/phemex.py +4 -4
  85. ccxt/async_support/poloniex.py +3 -3
  86. ccxt/async_support/poloniexfutures.py +2 -2
  87. ccxt/async_support/probit.py +3 -3
  88. ccxt/async_support/timex.py +2 -2
  89. ccxt/async_support/tokocrypto.py +1 -1
  90. ccxt/async_support/tradeogre.py +1 -1
  91. ccxt/async_support/upbit.py +3 -3
  92. ccxt/async_support/wavesexchange.py +1 -1
  93. ccxt/async_support/wazirx.py +3 -3
  94. ccxt/async_support/whitebit.py +3 -3
  95. ccxt/async_support/woo.py +3 -3
  96. ccxt/async_support/woofipro.py +3 -3
  97. ccxt/async_support/yobit.py +1 -1
  98. ccxt/async_support/zaif.py +2 -2
  99. ccxt/async_support/zonda.py +1 -1
  100. ccxt/base/exchange.py +25 -3
  101. ccxt/base/types.py +0 -1
  102. ccxt/bigone.py +2 -2
  103. ccxt/binance.py +4 -3
  104. ccxt/bingx.py +2 -2
  105. ccxt/bit2c.py +1 -1
  106. ccxt/bitbank.py +1 -1
  107. ccxt/bitbns.py +1 -1
  108. ccxt/bitfinex.py +2 -2
  109. ccxt/bitfinex2.py +1 -1
  110. ccxt/bitflyer.py +1 -1
  111. ccxt/bitget.py +3 -3
  112. ccxt/bithumb.py +1 -1
  113. ccxt/bitmart.py +2 -2
  114. ccxt/bitmex.py +3 -3
  115. ccxt/bitopro.py +3 -3
  116. ccxt/bitrue.py +2 -2
  117. ccxt/bitso.py +2 -2
  118. ccxt/bitstamp.py +2 -2
  119. ccxt/bitteam.py +3 -3
  120. ccxt/bitvavo.py +2 -2
  121. ccxt/blockchaincom.py +1 -1
  122. ccxt/blofin.py +3 -3
  123. ccxt/btcalpha.py +3 -3
  124. ccxt/btcbox.py +1 -1
  125. ccxt/btcmarkets.py +3 -3
  126. ccxt/btcturk.py +1 -1
  127. ccxt/bybit.py +2 -2
  128. ccxt/cex.py +1 -1
  129. ccxt/coinbase.py +96 -55
  130. ccxt/coinbaseexchange.py +1 -1
  131. ccxt/coinbaseinternational.py +3 -3
  132. ccxt/coincheck.py +2 -2
  133. ccxt/coinex.py +2 -2
  134. ccxt/coinlist.py +2 -2
  135. ccxt/coinmate.py +2 -2
  136. ccxt/coinmetro.py +2 -2
  137. ccxt/coinone.py +1 -1
  138. ccxt/coinsph.py +2 -2
  139. ccxt/cryptocom.py +1 -1
  140. ccxt/currencycom.py +2 -2
  141. ccxt/delta.py +1 -1
  142. ccxt/deribit.py +2 -2
  143. ccxt/digifinex.py +2 -2
  144. ccxt/exmo.py +2 -2
  145. ccxt/gate.py +2 -2
  146. ccxt/gemini.py +2 -2
  147. ccxt/hitbtc.py +2 -2
  148. ccxt/hollaex.py +1 -1
  149. ccxt/htx.py +2 -2
  150. ccxt/huobijp.py +2 -2
  151. ccxt/hyperliquid.py +2 -2
  152. ccxt/idex.py +2 -2
  153. ccxt/indodax.py +2 -2
  154. ccxt/kraken.py +2 -2
  155. ccxt/krakenfutures.py +1 -1
  156. ccxt/kucoin.py +2 -2
  157. ccxt/kuna.py +2 -2
  158. ccxt/latoken.py +2 -2
  159. ccxt/lbank.py +1 -1
  160. ccxt/luno.py +1 -1
  161. ccxt/lykke.py +1 -1
  162. ccxt/mercado.py +1 -1
  163. ccxt/mexc.py +1 -1
  164. ccxt/ndax.py +2 -2
  165. ccxt/novadax.py +3 -3
  166. ccxt/oceanex.py +2 -2
  167. ccxt/okcoin.py +3 -3
  168. ccxt/okx.py +3 -3
  169. ccxt/onetrading.py +2 -2
  170. ccxt/p2b.py +2 -2
  171. ccxt/paymium.py +1 -1
  172. ccxt/phemex.py +4 -4
  173. ccxt/poloniex.py +3 -3
  174. ccxt/poloniexfutures.py +2 -2
  175. ccxt/pro/__init__.py +1 -1
  176. ccxt/pro/binance.py +331 -2
  177. ccxt/pro/bitmex.py +98 -1
  178. ccxt/pro/bybit.py +82 -1
  179. ccxt/pro/gate.py +173 -1
  180. ccxt/pro/kucoinfutures.py +4 -0
  181. ccxt/pro/okx.py +245 -2
  182. ccxt/probit.py +3 -3
  183. ccxt/test/base/__init__.py +1 -0
  184. ccxt/test/base/test_liquidation.py +50 -0
  185. ccxt/timex.py +2 -2
  186. ccxt/tokocrypto.py +1 -1
  187. ccxt/tradeogre.py +1 -1
  188. ccxt/upbit.py +3 -3
  189. ccxt/wavesexchange.py +1 -1
  190. ccxt/wazirx.py +3 -3
  191. ccxt/whitebit.py +3 -3
  192. ccxt/woo.py +3 -3
  193. ccxt/woofipro.py +3 -3
  194. ccxt/yobit.py +1 -1
  195. ccxt/zaif.py +2 -2
  196. ccxt/zonda.py +1 -1
  197. {ccxt-4.3.33.dist-info → ccxt-4.3.34.dist-info}/METADATA +4 -4
  198. {ccxt-4.3.33.dist-info → ccxt-4.3.34.dist-info}/RECORD +200 -199
  199. {ccxt-4.3.33.dist-info → ccxt-4.3.34.dist-info}/WHEEL +0 -0
  200. {ccxt-4.3.33.dist-info → ccxt-4.3.34.dist-info}/top_level.txt +0 -0
ccxt/pro/binance.py CHANGED
@@ -6,7 +6,7 @@
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Int, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
9
+ from ccxt.base.types import Balances, Int, Liquidation, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import ArgumentsRequired
@@ -23,6 +23,10 @@ class binance(ccxt.async_support.binance):
23
23
  'has': {
24
24
  'ws': True,
25
25
  'watchBalance': True,
26
+ 'watchLiquidations': True,
27
+ 'watchLiquidationsForSymbols': True,
28
+ 'watchMyLiquidations': True,
29
+ 'watchMyLiquidationsForSymbols': True,
26
30
  'watchBidsAsks': True,
27
31
  'watchMyTrades': True,
28
32
  'watchOHLCV': True,
@@ -107,6 +111,8 @@ class binance(ccxt.async_support.binance):
107
111
  # get updates every 1000ms or 100ms
108
112
  # or every 0ms in real-time for futures
109
113
  'watchOrderBookRate': 100,
114
+ 'liquidationsLimit': 1000,
115
+ 'myLiquidationsLimit': 1000,
110
116
  'tradesLimit': 1000,
111
117
  'ordersLimit': 1000,
112
118
  'OHLCVLimit': 1000,
@@ -131,6 +137,9 @@ class binance(ccxt.async_support.binance):
131
137
  'fetchBalanceSnapshot': False, # or True
132
138
  'awaitBalanceSnapshot': True, # whether to wait for the balance snapshot before providing updates
133
139
  },
140
+ 'watchLiquidationsForSymbols': {
141
+ 'defaultType': 'swap',
142
+ },
134
143
  'watchPositions': {
135
144
  'fetchPositionsSnapshot': True, # or False
136
145
  'awaitPositionsSnapshot': True, # whether to wait for the positions snapshot before providing updates
@@ -159,7 +168,7 @@ class binance(ccxt.async_support.binance):
159
168
  self.options['requestId'][url] = newValue
160
169
  return newValue
161
170
 
162
- def stream(self, type, subscriptionHash, numSubscriptions=1):
171
+ def stream(self, type: Str, subscriptionHash: Str, numSubscriptions=1):
163
172
  streamBySubscriptionsHash = self.safe_dict(self.options, 'streamBySubscriptionsHash', self.create_safe_dictionary())
164
173
  stream = self.safe_string(streamBySubscriptionsHash, subscriptionHash)
165
174
  if stream is None:
@@ -182,6 +191,324 @@ class binance(ccxt.async_support.binance):
182
191
  self.options['numSubscriptionsByStream'][stream] = subscriptionsByStream + numSubscriptions
183
192
  return stream
184
193
 
194
+ async def watch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
195
+ """
196
+ watch the public liquidations of a trading pair
197
+ :see: https://binance-docs.github.io/apidocs/futures/en/#liquidation-order-streams
198
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#liquidation-order-streams
199
+ :param str symbol: unified CCXT market symbol
200
+ :param int [since]: the earliest time in ms to fetch liquidations for
201
+ :param int [limit]: the maximum number of liquidation structures to retrieve
202
+ :param dict [params]: exchange specific parameters for the bitmex api endpoint
203
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
204
+ """
205
+ return self.watch_liquidations_for_symbols([symbol], since, limit, params)
206
+
207
+ async def watch_liquidations_for_symbols(self, symbols: List[str] = None, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
208
+ """
209
+ watch the public liquidations of a trading pair
210
+ :see: https://binance-docs.github.io/apidocs/futures/en/#all-market-liquidation-order-streams
211
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#all-market-liquidation-order-streams
212
+ :param str symbol: unified CCXT market symbol
213
+ :param int [since]: the earliest time in ms to fetch liquidations for
214
+ :param int [limit]: the maximum number of liquidation structures to retrieve
215
+ :param dict [params]: exchange specific parameters for the bitmex api endpoint
216
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
217
+ """
218
+ await self.load_markets()
219
+ subscriptionHashes = []
220
+ messageHashes = []
221
+ streamHash = 'liquidations'
222
+ symbols = self.market_symbols(symbols, None, True, True)
223
+ if self.is_empty(symbols):
224
+ subscriptionHashes.append('!' + 'forceOrder@arr')
225
+ messageHashes.append('liquidations')
226
+ else:
227
+ for i in range(0, len(symbols)):
228
+ market = self.market(symbols[i])
229
+ subscriptionHashes.append(market['id'] + '@forceOrder')
230
+ messageHashes.append('liquidations::' + symbols[i])
231
+ streamHash += '::' + ','.join(symbols)
232
+ firstMarket = self.get_market_from_symbols(symbols)
233
+ type = None
234
+ type, params = self.handle_market_type_and_params('watchLiquidationsForSymbols', firstMarket, params)
235
+ if type == 'spot':
236
+ raise BadRequest(self.id + 'watchLiquidationsForSymbols is not supported for swap symbols')
237
+ subType = None
238
+ subType, params = self.handle_sub_type_and_params('watchLiquidationsForSymbols', firstMarket, params)
239
+ if self.isLinear(type, subType):
240
+ type = 'future'
241
+ elif self.isInverse(type, subType):
242
+ type = 'delivery'
243
+ numSubscriptions = len(subscriptionHashes)
244
+ url = self.urls['api']['ws'][type] + '/' + self.stream(type, streamHash, numSubscriptions)
245
+ requestId = self.request_id(url)
246
+ request = {
247
+ 'method': 'SUBSCRIBE',
248
+ 'params': subscriptionHashes,
249
+ 'id': requestId,
250
+ }
251
+ subscribe = {
252
+ 'id': requestId,
253
+ }
254
+ newLiquidations = await self.watch_multiple(url, messageHashes, self.extend(request, params), subscriptionHashes, subscribe)
255
+ if self.newUpdates:
256
+ return newLiquidations
257
+ return self.filter_by_symbols_since_limit(self.liquidations, symbols, since, limit, True)
258
+
259
+ def handle_liquidation(self, client: Client, message):
260
+ #
261
+ # future
262
+ # {
263
+ # "e":"forceOrder",
264
+ # "E":1698871323061,
265
+ # "o":{
266
+ # "s":"BTCUSDT",
267
+ # "S":"BUY",
268
+ # "o":"LIMIT",
269
+ # "f":"IOC",
270
+ # "q":"1.437",
271
+ # "p":"35100.81",
272
+ # "ap":"34959.70",
273
+ # "X":"FILLED",
274
+ # "l":"1.437",
275
+ # "z":"1.437",
276
+ # "T":1698871323059
277
+ # }
278
+ # }
279
+ # delivery
280
+ # {
281
+ # "e":"forceOrder", # Event Type
282
+ # "E": 1591154240950, # Event Time
283
+ # "o":{
284
+ # "s":"BTCUSD_200925", # Symbol
285
+ # "ps": "BTCUSD", # Pair
286
+ # "S":"SELL", # Side
287
+ # "o":"LIMIT", # Order Type
288
+ # "f":"IOC", # Time in Force
289
+ # "q":"1", # Original Quantity
290
+ # "p":"9425.5", # Price
291
+ # "ap":"9496.5", # Average Price
292
+ # "X":"FILLED", # Order Status
293
+ # "l":"1", # Order Last Filled Quantity
294
+ # "z":"1", # Order Filled Accumulated Quantity
295
+ # "T": 1591154240949, # Order Trade Time
296
+ # }
297
+ # }
298
+ #
299
+ rawLiquidation = self.safe_value(message, 'o', {})
300
+ marketId = self.safe_string(rawLiquidation, 's')
301
+ market = self.safe_market(marketId, None, '', 'contract')
302
+ symbol = market['symbol']
303
+ liquidation = self.parse_ws_liquidation(rawLiquidation, market)
304
+ liquidations = self.safe_value(self.liquidations, symbol)
305
+ if liquidations is None:
306
+ limit = self.safe_integer(self.options, 'liquidationsLimit', 1000)
307
+ liquidations = ArrayCache(limit)
308
+ liquidations.append(liquidation)
309
+ self.liquidations[symbol] = liquidations
310
+ client.resolve([liquidation], 'liquidations')
311
+ client.resolve([liquidation], 'liquidations::' + symbol)
312
+
313
+ def parse_ws_liquidation(self, liquidation, market=None):
314
+ #
315
+ # future
316
+ # {
317
+ # "s":"BTCUSDT",
318
+ # "S":"BUY",
319
+ # "o":"LIMIT",
320
+ # "f":"IOC",
321
+ # "q":"1.437",
322
+ # "p":"35100.81",
323
+ # "ap":"34959.70",
324
+ # "X":"FILLED",
325
+ # "l":"1.437",
326
+ # "z":"1.437",
327
+ # "T":1698871323059
328
+ # }
329
+ # delivery
330
+ # {
331
+ # "s":"BTCUSD_200925", # Symbol
332
+ # "ps": "BTCUSD", # Pair
333
+ # "S":"SELL", # Side
334
+ # "o":"LIMIT", # Order Type
335
+ # "f":"IOC", # Time in Force
336
+ # "q":"1", # Original Quantity
337
+ # "p":"9425.5", # Price
338
+ # "ap":"9496.5", # Average Price
339
+ # "X":"FILLED", # Order Status
340
+ # "l":"1", # Order Last Filled Quantity
341
+ # "z":"1", # Order Filled Accumulated Quantity
342
+ # "T": 1591154240949, # Order Trade Time
343
+ # }
344
+ # myLiquidation
345
+ # {
346
+ # "s":"BTCUSDT", # Symbol
347
+ # "c":"TEST", # Client Order Id
348
+ # # special client order id:
349
+ # # starts with "autoclose-": liquidation order
350
+ # # "adl_autoclose": ADL auto close order
351
+ # # "settlement_autoclose-": settlement order for delisting or delivery
352
+ # "S":"SELL", # Side
353
+ # "o":"TRAILING_STOP_MARKET", # Order Type
354
+ # "f":"GTC", # Time in Force
355
+ # "q":"0.001", # Original Quantity
356
+ # "p":"0", # Original Price
357
+ # "ap":"0", # Average Price
358
+ # "sp":"7103.04", # Stop Price. Please ignore with TRAILING_STOP_MARKET order
359
+ # "x":"NEW", # Execution Type
360
+ # "X":"NEW", # Order Status
361
+ # "i":8886774, # Order Id
362
+ # "l":"0", # Order Last Filled Quantity
363
+ # "z":"0", # Order Filled Accumulated Quantity
364
+ # "L":"0", # Last Filled Price
365
+ # "N":"USDT", # Commission Asset, will not push if no commission
366
+ # "n":"0", # Commission, will not push if no commission
367
+ # "T":1568879465650, # Order Trade Time
368
+ # "t":0, # Trade Id
369
+ # "b":"0", # Bids Notional
370
+ # "a":"9.91", # Ask Notional
371
+ # "m":false, # Is self trade the maker side?
372
+ # "R":false, # Is self reduce only
373
+ # "wt":"CONTRACT_PRICE", # Stop Price Working Type
374
+ # "ot":"TRAILING_STOP_MARKET",// Original Order Type
375
+ # "ps":"LONG", # Position Side
376
+ # "cp":false, # If Close-All, pushed with conditional order
377
+ # "AP":"7476.89", # Activation Price, only puhed with TRAILING_STOP_MARKET order
378
+ # "cr":"5.0", # Callback Rate, only puhed with TRAILING_STOP_MARKET order
379
+ # "pP": False, # If price protection is turned on
380
+ # "si": 0, # ignore
381
+ # "ss": 0, # ignore
382
+ # "rp":"0", # Realized Profit of the trade
383
+ # "V":"EXPIRE_TAKER", # STP mode
384
+ # "pm":"OPPONENT", # Price match mode
385
+ # "gtd":0 # TIF GTD order auto cancel time
386
+ # }
387
+ #
388
+ marketId = self.safe_string(liquidation, 's')
389
+ market = self.safe_market(marketId, market)
390
+ timestamp = self.safe_integer(liquidation, 'T')
391
+ return self.safe_liquidation({
392
+ 'info': liquidation,
393
+ 'symbol': self.safe_symbol(marketId, market),
394
+ 'contracts': self.safe_number(liquidation, 'l'),
395
+ 'contractSize': self.safe_number(market, 'contractSize'),
396
+ 'price': self.safe_number(liquidation, 'ap'),
397
+ 'baseValue': None,
398
+ 'quoteValue': None,
399
+ 'timestamp': timestamp,
400
+ 'datetime': self.iso8601(timestamp),
401
+ })
402
+
403
+ async def watch_my_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
404
+ """
405
+ watch the private liquidations of a trading pair
406
+ :see: https://binance-docs.github.io/apidocs/futures/en/#event-order-update
407
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#event-order-update
408
+ :param str symbol: unified CCXT market symbol
409
+ :param int [since]: the earliest time in ms to fetch liquidations for
410
+ :param int [limit]: the maximum number of liquidation structures to retrieve
411
+ :param dict [params]: exchange specific parameters for the bitmex api endpoint
412
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
413
+ """
414
+ return self.watch_my_liquidations_for_symbols([symbol], since, limit, params)
415
+
416
+ async def watch_my_liquidations_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
417
+ """
418
+ watch the private liquidations of a trading pair
419
+ :see: https://binance-docs.github.io/apidocs/futures/en/#event-order-update
420
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#event-order-update
421
+ :param str symbol: unified CCXT market symbol
422
+ :param int [since]: the earliest time in ms to fetch liquidations for
423
+ :param int [limit]: the maximum number of liquidation structures to retrieve
424
+ :param dict [params]: exchange specific parameters for the bitmex api endpoint
425
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
426
+ """
427
+ await self.load_markets()
428
+ symbols = self.market_symbols(symbols, None, True, True, True)
429
+ market = self.get_market_from_symbols(symbols)
430
+ messageHashes = ['myLiquidations']
431
+ if not self.is_empty(symbols):
432
+ for i in range(0, len(symbols)):
433
+ symbol = symbols[i]
434
+ messageHashes.append('myLiquidations::' + symbol)
435
+ type = None
436
+ type, params = self.handle_market_type_and_params('watchMyLiquidationsForSymbols', market, params)
437
+ subType = None
438
+ subType, params = self.handle_sub_type_and_params('watchMyLiquidationsForSymbols', market, params)
439
+ if self.isLinear(type, subType):
440
+ type = 'future'
441
+ elif self.isInverse(type, subType):
442
+ type = 'delivery'
443
+ await self.authenticate(params)
444
+ url = self.urls['api']['ws'][type] + '/' + self.options[type]['listenKey']
445
+ message = None
446
+ newLiquidations = await self.watch_multiple(url, messageHashes, message, [type])
447
+ if self.newUpdates:
448
+ return newLiquidations
449
+ return self.filter_by_symbols_since_limit(self.liquidations, symbols, since, limit)
450
+
451
+ def handle_my_liquidation(self, client: Client, message):
452
+ #
453
+ # {
454
+ # "s":"BTCUSDT", # Symbol
455
+ # "c":"TEST", # Client Order Id
456
+ # # special client order id:
457
+ # # starts with "autoclose-": liquidation order
458
+ # # "adl_autoclose": ADL auto close order
459
+ # # "settlement_autoclose-": settlement order for delisting or delivery
460
+ # "S":"SELL", # Side
461
+ # "o":"TRAILING_STOP_MARKET", # Order Type
462
+ # "f":"GTC", # Time in Force
463
+ # "q":"0.001", # Original Quantity
464
+ # "p":"0", # Original Price
465
+ # "ap":"0", # Average Price
466
+ # "sp":"7103.04", # Stop Price. Please ignore with TRAILING_STOP_MARKET order
467
+ # "x":"NEW", # Execution Type
468
+ # "X":"NEW", # Order Status
469
+ # "i":8886774, # Order Id
470
+ # "l":"0", # Order Last Filled Quantity
471
+ # "z":"0", # Order Filled Accumulated Quantity
472
+ # "L":"0", # Last Filled Price
473
+ # "N":"USDT", # Commission Asset, will not push if no commission
474
+ # "n":"0", # Commission, will not push if no commission
475
+ # "T":1568879465650, # Order Trade Time
476
+ # "t":0, # Trade Id
477
+ # "b":"0", # Bids Notional
478
+ # "a":"9.91", # Ask Notional
479
+ # "m":false, # Is self trade the maker side?
480
+ # "R":false, # Is self reduce only
481
+ # "wt":"CONTRACT_PRICE", # Stop Price Working Type
482
+ # "ot":"TRAILING_STOP_MARKET",// Original Order Type
483
+ # "ps":"LONG", # Position Side
484
+ # "cp":false, # If Close-All, pushed with conditional order
485
+ # "AP":"7476.89", # Activation Price, only puhed with TRAILING_STOP_MARKET order
486
+ # "cr":"5.0", # Callback Rate, only puhed with TRAILING_STOP_MARKET order
487
+ # "pP": False, # If price protection is turned on
488
+ # "si": 0, # ignore
489
+ # "ss": 0, # ignore
490
+ # "rp":"0", # Realized Profit of the trade
491
+ # "V":"EXPIRE_TAKER", # STP mode
492
+ # "pm":"OPPONENT", # Price match mode
493
+ # "gtd":0 # TIF GTD order auto cancel time
494
+ # }
495
+ #
496
+ orderType = self.safe_string(message, 'o')
497
+ if orderType != 'LIQUIDATION':
498
+ return
499
+ marketId = self.safe_string(message, 's')
500
+ market = self.safe_market(marketId)
501
+ symbol = self.safe_symbol(marketId)
502
+ liquidation = self.parse_ws_liquidation(message, market)
503
+ myLiquidations = self.safe_value(self.myLiquidations, symbol)
504
+ if myLiquidations is None:
505
+ limit = self.safe_integer(self.options, 'myLiquidationsLimit', 1000)
506
+ myLiquidations = ArrayCache(limit)
507
+ myLiquidations.append(liquidation)
508
+ self.myLiquidations[symbol] = myLiquidations
509
+ client.resolve([liquidation], 'myLiquidations')
510
+ client.resolve([liquidation], 'myLiquidations::' + symbol)
511
+
185
512
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
186
513
  """
187
514
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
@@ -2590,6 +2917,7 @@ class binance(ccxt.async_support.binance):
2590
2917
  message = self.safe_dict(message, 'o', message)
2591
2918
  self.handle_my_trade(client, message)
2592
2919
  self.handle_order(client, message)
2920
+ self.handle_my_liquidation(client, message)
2593
2921
 
2594
2922
  async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
2595
2923
  """
@@ -3131,6 +3459,7 @@ class binance(ccxt.async_support.binance):
3131
3459
  'ACCOUNT_UPDATE': self.handle_acount_update,
3132
3460
  'executionReport': self.handle_order_update,
3133
3461
  'ORDER_TRADE_UPDATE': self.handle_order_update,
3462
+ 'forceOrder': self.handle_liquidation,
3134
3463
  }
3135
3464
  event = self.safe_string(message, 'e')
3136
3465
  if isinstance(message, list):
ccxt/pro/bitmex.py CHANGED
@@ -6,7 +6,7 @@
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Int, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
9
+ from ccxt.base.types import Balances, Int, Liquidation, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
@@ -21,6 +21,10 @@ class bitmex(ccxt.async_support.bitmex):
21
21
  'has': {
22
22
  'ws': True,
23
23
  'watchBalance': True,
24
+ 'watchLiquidations': True,
25
+ 'watchLiquidationsForSymbols': True,
26
+ 'watchMyLiquidations': None,
27
+ 'watchMyLiquidationsForSymbols': None,
24
28
  'watchMyTrades': True,
25
29
  'watchOHLCV': True,
26
30
  'watchOrderBook': True,
@@ -350,6 +354,98 @@ class bitmex(ccxt.async_support.bitmex):
350
354
  client.resolve(fullParsedTicker, 'alltickers')
351
355
  return message
352
356
 
357
+ async def watch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
358
+ """
359
+ watch the public liquidations of a trading pair
360
+ :see: https://www.bitmex.com/app/wsAPI#Liquidation
361
+ :param str symbol: unified CCXT market symbol
362
+ :param int [since]: the earliest time in ms to fetch liquidations for
363
+ :param int [limit]: the maximum number of liquidation structures to retrieve
364
+ :param dict [params]: exchange specific parameters for the bitmex api endpoint
365
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
366
+ """
367
+ return self.watch_liquidations_for_symbols([symbol], since, limit, params)
368
+
369
+ async def watch_liquidations_for_symbols(self, symbols: List[str] = None, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
370
+ """
371
+ watch the public liquidations of a trading pair
372
+ :see: https://www.bitmex.com/app/wsAPI#Liquidation
373
+ :param str symbol: unified CCXT market symbol
374
+ :param int [since]: the earliest time in ms to fetch liquidations for
375
+ :param int [limit]: the maximum number of liquidation structures to retrieve
376
+ :param dict [params]: exchange specific parameters for the bitmex api endpoint
377
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
378
+ """
379
+ await self.load_markets()
380
+ symbols = self.market_symbols(symbols, None, True, True)
381
+ messageHashes = []
382
+ subscriptionHashes = []
383
+ if self.is_empty(symbols):
384
+ subscriptionHashes.append('liquidation')
385
+ messageHashes.append('liquidations')
386
+ else:
387
+ for i in range(0, len(symbols)):
388
+ symbol = symbols[i]
389
+ market = self.market(symbol)
390
+ subscriptionHashes.append('liquidation:' + market['id'])
391
+ messageHashes.append('liquidations::' + symbol)
392
+ url = self.urls['api']['ws']
393
+ request = {
394
+ 'op': 'subscribe',
395
+ 'args': subscriptionHashes,
396
+ }
397
+ newLiquidations = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), subscriptionHashes)
398
+ if self.newUpdates:
399
+ return newLiquidations
400
+ return self.filter_by_symbols_since_limit(self.liquidations, symbols, since, limit, True)
401
+
402
+ def handle_liquidation(self, client: Client, message):
403
+ #
404
+ # {
405
+ # "table":"liquidation",
406
+ # "action":"partial",
407
+ # "keys":[
408
+ # "orderID"
409
+ # ],
410
+ # "types":{
411
+ # "orderID":"guid",
412
+ # "symbol":"symbol",
413
+ # "side":"symbol",
414
+ # "price":"float",
415
+ # "leavesQty":"long"
416
+ # },
417
+ # "filter":{},
418
+ # "data":[
419
+ # {
420
+ # "orderID":"e0a568ee-7830-4428-92c3-73e82b9576ce",
421
+ # "symbol":"XPLAUSDT",
422
+ # "side":"Sell",
423
+ # "price":0.206,
424
+ # "leavesQty":340
425
+ # }
426
+ # ]
427
+ # }
428
+ #
429
+ rawLiquidations = self.safe_value(message, 'data', [])
430
+ newLiquidations = []
431
+ for i in range(0, len(rawLiquidations)):
432
+ rawLiquidation = rawLiquidations[i]
433
+ liquidation = self.parse_liquidation(rawLiquidation)
434
+ symbol = liquidation['symbol']
435
+ liquidations = self.safe_value(self.liquidations, symbol)
436
+ if liquidations is None:
437
+ limit = self.safe_integer(self.options, 'liquidationsLimit', 1000)
438
+ liquidations = ArrayCache(limit)
439
+ liquidations.append(liquidation)
440
+ self.liquidations[symbol] = liquidations
441
+ newLiquidations.append(liquidation)
442
+ client.resolve(newLiquidations, 'liquidations')
443
+ liquidationsBySymbol = self.index_by(newLiquidations, 'symbol')
444
+ symbols = list(liquidationsBySymbol.keys())
445
+ for i in range(0, len(symbols)):
446
+ symbol = symbols[i]
447
+ client.resolve(liquidationsBySymbol[symbol], 'liquidations::' + symbol)
448
+
353
449
  async def watch_balance(self, params={}) -> Balances:
354
450
  """
355
451
  watch balance and get the amount of funds available for trading or funds locked in orders
@@ -1541,6 +1637,7 @@ class bitmex(ccxt.async_support.bitmex):
1541
1637
  'order': self.handle_orders,
1542
1638
  'execution': self.handle_my_trades,
1543
1639
  'margin': self.handle_balance,
1640
+ 'liquidation': self.handle_liquidation,
1544
1641
  'position': self.handle_positions,
1545
1642
  }
1546
1643
  method = self.safe_value(methods, table)
ccxt/pro/bybit.py CHANGED
@@ -7,7 +7,7 @@ import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
8
8
  import asyncio
9
9
  import hashlib
10
- from ccxt.base.types import Balances, Int, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
10
+ from ccxt.base.types import Balances, Int, Liquidation, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
11
11
  from ccxt.async_support.base.ws.client import Client
12
12
  from typing import List
13
13
  from ccxt.base.errors import ExchangeError
@@ -32,6 +32,10 @@ class bybit(ccxt.async_support.bybit):
32
32
  'fetchTradesWs': False,
33
33
  'fetchBalanceWs': False,
34
34
  'watchBalance': True,
35
+ 'watchLiquidations': True,
36
+ 'watchLiquidationsForSymbols': False,
37
+ 'watchMyLiquidations': False,
38
+ 'watchMyLiquidationsForSymbols': False,
35
39
  'watchMyTrades': True,
36
40
  'watchOHLCV': True,
37
41
  'watchOHLCVForSymbols': False,
@@ -1124,6 +1128,82 @@ class bybit(ccxt.async_support.bybit):
1124
1128
  client.resolve(positions, messageHash)
1125
1129
  client.resolve(newPositions, 'positions')
1126
1130
 
1131
+ async def watch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
1132
+ """
1133
+ watch the public liquidations of a trading pair
1134
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/liquidation
1135
+ :param str symbol: unified CCXT market symbol
1136
+ :param int [since]: the earliest time in ms to fetch liquidations for
1137
+ :param int [limit]: the maximum number of liquidation structures to retrieve
1138
+ :param dict [params]: exchange specific parameters for the bitmex api endpoint
1139
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
1140
+ """
1141
+ await self.load_markets()
1142
+ market = self.market(symbol)
1143
+ symbol = market['symbol']
1144
+ url = self.get_url_by_market_type(symbol, False, 'watchLiquidations', params)
1145
+ params = self.clean_params(params)
1146
+ messageHash = 'liquidations::' + symbol
1147
+ topic = 'liquidation.' + market['id']
1148
+ newLiquidation = await self.watch_topics(url, [messageHash], [topic], params)
1149
+ if self.newUpdates:
1150
+ return [newLiquidation]
1151
+ return self.filter_by_symbols_since_limit(self.liquidations, [symbol], since, limit, True)
1152
+
1153
+ def handle_liquidation(self, client: Client, message):
1154
+ #
1155
+ # {
1156
+ # "data": {
1157
+ # "price": "0.03803",
1158
+ # "side": "Buy",
1159
+ # "size": "1637",
1160
+ # "symbol": "GALAUSDT",
1161
+ # "updatedTime": 1673251091822
1162
+ # },
1163
+ # "topic": "liquidation.GALAUSDT",
1164
+ # "ts": 1673251091822,
1165
+ # "type": "snapshot"
1166
+ # }
1167
+ #
1168
+ rawLiquidation = self.safe_dict(message, 'data', {})
1169
+ marketId = self.safe_string(rawLiquidation, 'symbol')
1170
+ market = self.safe_market(marketId, None, '', 'contract')
1171
+ symbol = self.safe_symbol(marketId)
1172
+ liquidation = self.parse_ws_liquidation(rawLiquidation, market)
1173
+ liquidations = self.safe_value(self.liquidations, symbol)
1174
+ if liquidations is None:
1175
+ limit = self.safe_integer(self.options, 'liquidationsLimit', 1000)
1176
+ liquidations = ArrayCache(limit)
1177
+ liquidations.append(liquidation)
1178
+ self.liquidations[symbol] = liquidations
1179
+ client.resolve([liquidation], 'liquidations')
1180
+ client.resolve([liquidation], 'liquidations::' + symbol)
1181
+
1182
+ def parse_ws_liquidation(self, liquidation, market=None):
1183
+ #
1184
+ # {
1185
+ # "price": "0.03803",
1186
+ # "side": "Buy",
1187
+ # "size": "1637",
1188
+ # "symbol": "GALAUSDT",
1189
+ # "updatedTime": 1673251091822
1190
+ # }
1191
+ #
1192
+ marketId = self.safe_string(liquidation, 'symbol')
1193
+ market = self.safe_market(marketId, market, '', 'contract')
1194
+ timestamp = self.safe_integer(liquidation, 'updatedTime')
1195
+ return self.safe_liquidation({
1196
+ 'info': liquidation,
1197
+ 'symbol': self.safe_symbol(marketId, market),
1198
+ 'contracts': self.safe_number(liquidation, 'size'),
1199
+ 'contractSize': self.safe_number(market, 'contractSize'),
1200
+ 'price': self.safe_number(liquidation, 'price'),
1201
+ 'baseValue': None,
1202
+ 'quoteValue': None,
1203
+ 'timestamp': timestamp,
1204
+ 'datetime': self.iso8601(timestamp),
1205
+ })
1206
+
1127
1207
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1128
1208
  """
1129
1209
  watches information on multiple orders made by the user
@@ -1830,6 +1910,7 @@ class bybit(ccxt.async_support.bybit):
1830
1910
  'ticketInfo': self.handle_my_trades,
1831
1911
  'user.openapi.perp.trade': self.handle_my_trades,
1832
1912
  'position': self.handle_positions,
1913
+ 'liquidation': self.handle_liquidation,
1833
1914
  'pong': self.handle_pong,
1834
1915
  'order.create': self.handle_order_ws,
1835
1916
  'order.amend': self.handle_order_ws,