ccxt 4.4.82__py2.py3-none-any.whl → 4.4.86__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 (121) hide show
  1. ccxt/__init__.py +3 -9
  2. ccxt/abstract/blofin.py +8 -0
  3. ccxt/abstract/btcbox.py +1 -0
  4. ccxt/abstract/myokx.py +2 -0
  5. ccxt/abstract/okx.py +2 -0
  6. ccxt/apex.py +2 -1
  7. ccxt/ascendex.py +187 -151
  8. ccxt/async_support/__init__.py +3 -9
  9. ccxt/async_support/apex.py +2 -1
  10. ccxt/async_support/ascendex.py +187 -151
  11. ccxt/async_support/base/exchange.py +51 -24
  12. ccxt/async_support/base/ws/cache.py +6 -1
  13. ccxt/async_support/bequant.py +1 -1
  14. ccxt/async_support/bitget.py +5 -6
  15. ccxt/async_support/bitmart.py +1 -1
  16. ccxt/async_support/bitrue.py +14 -32
  17. ccxt/async_support/bitso.py +33 -0
  18. ccxt/async_support/bitstamp.py +33 -0
  19. ccxt/async_support/{huobijp.py → bittrade.py} +11 -11
  20. ccxt/async_support/blofin.py +145 -14
  21. ccxt/async_support/btcbox.py +25 -5
  22. ccxt/async_support/bybit.py +16 -37
  23. ccxt/async_support/cex.py +2 -4
  24. ccxt/async_support/coinbase.py +58 -47
  25. ccxt/async_support/coinbaseexchange.py +141 -32
  26. ccxt/async_support/coincatch.py +14 -67
  27. ccxt/async_support/coinex.py +28 -29
  28. ccxt/async_support/coinlist.py +17 -16
  29. ccxt/async_support/coinmetro.py +20 -11
  30. ccxt/async_support/coinone.py +8 -10
  31. ccxt/async_support/coinsph.py +124 -2
  32. ccxt/async_support/cryptocom.py +109 -2
  33. ccxt/async_support/cryptomus.py +42 -80
  34. ccxt/async_support/delta.py +75 -36
  35. ccxt/async_support/deribit.py +4 -5
  36. ccxt/async_support/derive.py +46 -10
  37. ccxt/async_support/ellipx.py +175 -77
  38. ccxt/async_support/gate.py +1 -1
  39. ccxt/async_support/gemini.py +3 -4
  40. ccxt/async_support/hitbtc.py +56 -65
  41. ccxt/async_support/hollaex.py +106 -49
  42. ccxt/async_support/htx.py +20 -43
  43. ccxt/async_support/hyperliquid.py +6 -6
  44. ccxt/async_support/kraken.py +27 -23
  45. ccxt/async_support/kucoinfutures.py +5 -0
  46. ccxt/async_support/lbank.py +1 -1
  47. ccxt/async_support/mexc.py +2 -2
  48. ccxt/async_support/ndax.py +25 -24
  49. ccxt/async_support/okcoin.py +12 -29
  50. ccxt/async_support/okx.py +9 -0
  51. ccxt/async_support/onetrading.py +10 -7
  52. ccxt/async_support/oxfun.py +40 -110
  53. ccxt/async_support/paradex.py +123 -4
  54. ccxt/base/exchange.py +21 -2
  55. ccxt/base/types.py +3 -0
  56. ccxt/bequant.py +1 -1
  57. ccxt/bitget.py +5 -6
  58. ccxt/bitmart.py +1 -1
  59. ccxt/bitrue.py +14 -32
  60. ccxt/bitso.py +33 -0
  61. ccxt/bitstamp.py +33 -0
  62. ccxt/{huobijp.py → bittrade.py} +11 -11
  63. ccxt/blofin.py +145 -14
  64. ccxt/btcbox.py +24 -5
  65. ccxt/bybit.py +16 -37
  66. ccxt/cex.py +2 -4
  67. ccxt/coinbase.py +58 -47
  68. ccxt/coinbaseexchange.py +141 -32
  69. ccxt/coincatch.py +14 -67
  70. ccxt/coinex.py +28 -29
  71. ccxt/coinlist.py +17 -16
  72. ccxt/coinmetro.py +20 -11
  73. ccxt/coinone.py +8 -10
  74. ccxt/coinsph.py +124 -2
  75. ccxt/cryptocom.py +109 -2
  76. ccxt/cryptomus.py +42 -80
  77. ccxt/delta.py +75 -36
  78. ccxt/deribit.py +4 -5
  79. ccxt/derive.py +46 -10
  80. ccxt/ellipx.py +175 -77
  81. ccxt/gate.py +1 -1
  82. ccxt/gemini.py +3 -4
  83. ccxt/hitbtc.py +56 -65
  84. ccxt/hollaex.py +106 -49
  85. ccxt/htx.py +20 -43
  86. ccxt/hyperliquid.py +6 -6
  87. ccxt/kraken.py +27 -23
  88. ccxt/kucoinfutures.py +5 -0
  89. ccxt/lbank.py +1 -1
  90. ccxt/mexc.py +2 -2
  91. ccxt/ndax.py +25 -24
  92. ccxt/okcoin.py +12 -29
  93. ccxt/okx.py +9 -0
  94. ccxt/onetrading.py +10 -7
  95. ccxt/oxfun.py +40 -110
  96. ccxt/paradex.py +123 -4
  97. ccxt/pro/__init__.py +109 -5
  98. ccxt/pro/binance.py +32 -33
  99. ccxt/pro/bithumb.py +5 -3
  100. ccxt/pro/{huobijp.py → bittrade.py} +3 -3
  101. ccxt/pro/kraken.py +249 -79
  102. ccxt/pro/luno.py +6 -5
  103. ccxt/pro/mexc.py +254 -7
  104. ccxt/pro/poloniex.py +6 -2
  105. {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/METADATA +8 -11
  106. {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/RECORD +110 -121
  107. ccxt/abstract/bl3p.py +0 -19
  108. ccxt/abstract/idex.py +0 -26
  109. ccxt/abstract/kuna.py +0 -182
  110. ccxt/async_support/base/ws/fast_client.py +0 -97
  111. ccxt/async_support/bl3p.py +0 -543
  112. ccxt/async_support/idex.py +0 -1889
  113. ccxt/async_support/kuna.py +0 -1935
  114. ccxt/bl3p.py +0 -543
  115. ccxt/idex.py +0 -1889
  116. ccxt/kuna.py +0 -1935
  117. ccxt/pro/idex.py +0 -687
  118. /ccxt/abstract/{huobijp.py → bittrade.py} +0 -0
  119. {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/LICENSE.txt +0 -0
  120. {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/WHEEL +0 -0
  121. {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/top_level.txt +0 -0
ccxt/pro/kraken.py CHANGED
@@ -12,6 +12,7 @@ from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import AuthenticationError
13
13
  from ccxt.base.errors import PermissionDenied
14
14
  from ccxt.base.errors import AccountSuspended
15
+ from ccxt.base.errors import ArgumentsRequired
15
16
  from ccxt.base.errors import BadRequest
16
17
  from ccxt.base.errors import BadSymbol
17
18
  from ccxt.base.errors import InsufficientFunds
@@ -127,12 +128,133 @@ class kraken(ccxt.async_support.kraken):
127
128
  },
128
129
  })
129
130
 
131
+ def order_request_ws(self, method: str, symbol: str, type: str, request: dict, amount: Num, price: Num = None, params={}):
132
+ isLimitOrder = type.endswith('limit') # supporting limit, stop-loss-limit, take-profit-limit, etc
133
+ if isLimitOrder:
134
+ if price is None:
135
+ raise ArgumentsRequired(self.id + ' limit orders require a price argument')
136
+ request['params']['limit_price'] = self.parse_to_numeric(self.price_to_precision(symbol, price))
137
+ isMarket = (type == 'market')
138
+ postOnly = None
139
+ postOnly, params = self.handle_post_only(isMarket, False, params)
140
+ if postOnly:
141
+ request['params']['post_only'] = True
142
+ clientOrderId = self.safe_string(params, 'clientOrderId')
143
+ if clientOrderId is not None:
144
+ request['params']['cl_ord_id'] = clientOrderId
145
+ cost = self.safe_string(params, 'cost')
146
+ if cost is not None:
147
+ request['params']['order_qty'] = self.parse_to_numeric(self.cost_to_precision(symbol, cost))
148
+ stopLoss = self.safe_dict(params, 'stopLoss', {})
149
+ takeProfit = self.safe_dict(params, 'takeProfit', {})
150
+ presetStopLoss = self.safe_string(stopLoss, 'triggerPrice')
151
+ presetTakeProfit = self.safe_string(takeProfit, 'triggerPrice')
152
+ presetStopLossLimit = self.safe_string(stopLoss, 'price')
153
+ presetTakeProfitLimit = self.safe_string(takeProfit, 'price')
154
+ isPresetStopLoss = presetStopLoss is not None
155
+ isPresetTakeProfit = presetTakeProfit is not None
156
+ stopLossPrice = self.safe_string(params, 'stopLossPrice')
157
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
158
+ isStopLossPriceOrder = stopLossPrice is not None
159
+ isTakeProfitPriceOrder = takeProfitPrice is not None
160
+ trailingAmount = self.safe_string(params, 'trailingAmount')
161
+ trailingPercent = self.safe_string(params, 'trailingPercent')
162
+ trailingLimitAmount = self.safe_string(params, 'trailingLimitAmount')
163
+ trailingLimitPercent = self.safe_string(params, 'trailingLimitPercent')
164
+ isTrailingAmountOrder = trailingAmount is not None
165
+ isTrailingPercentOrder = trailingPercent is not None
166
+ isTrailingLimitAmountOrder = trailingLimitAmount is not None
167
+ isTrailingLimitPercentOrder = trailingLimitPercent is not None
168
+ offset = self.safe_string(params, 'offset', '') # can set self to - for minus
169
+ trailingAmountString = offset + self.number_to_string(trailingAmount) if (trailingAmount is not None) else None
170
+ trailingPercentString = offset + self.number_to_string(trailingPercent) if (trailingPercent is not None) else None
171
+ trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount) if (trailingLimitAmount is not None) else None
172
+ trailingLimitPercentString = offset + self.number_to_string(trailingLimitPercent) if (trailingLimitPercent is not None) else None
173
+ priceType = 'pct' if (isTrailingPercentOrder or isTrailingLimitPercentOrder) else 'quote'
174
+ if method == 'createOrderWs':
175
+ reduceOnly = self.safe_bool(params, 'reduceOnly')
176
+ if reduceOnly:
177
+ request['params']['reduce_only'] = True
178
+ timeInForce = self.safe_string_lower(params, 'timeInForce')
179
+ if timeInForce is not None:
180
+ request['params']['time_in_force'] = timeInForce
181
+ params = self.omit(params, ['reduceOnly', 'timeInForce'])
182
+ if isStopLossPriceOrder or isTakeProfitPriceOrder or isTrailingAmountOrder or isTrailingPercentOrder or isTrailingLimitAmountOrder or isTrailingLimitPercentOrder:
183
+ request['params']['triggers'] = {}
184
+ if isPresetStopLoss or isPresetTakeProfit:
185
+ request['params']['conditional'] = {}
186
+ if isPresetStopLoss:
187
+ request['params']['conditional']['order_type'] = 'stop-loss'
188
+ request['params']['conditional']['trigger_price'] = self.parse_to_numeric(self.price_to_precision(symbol, presetStopLoss))
189
+ elif isPresetTakeProfit:
190
+ request['params']['conditional']['order_type'] = 'take-profit'
191
+ request['params']['conditional']['trigger_price'] = self.parse_to_numeric(self.price_to_precision(symbol, presetTakeProfit))
192
+ if presetStopLossLimit is not None:
193
+ request['params']['conditional']['order_type'] = 'stop-loss-limit'
194
+ request['params']['conditional']['limit_price'] = self.parse_to_numeric(self.price_to_precision(symbol, presetStopLossLimit))
195
+ elif presetTakeProfitLimit is not None:
196
+ request['params']['conditional']['order_type'] = 'take-profit-limit'
197
+ request['params']['conditional']['limit_price'] = self.parse_to_numeric(self.price_to_precision(symbol, presetTakeProfitLimit))
198
+ params = self.omit(params, ['stopLoss', 'takeProfit'])
199
+ elif isStopLossPriceOrder or isTakeProfitPriceOrder:
200
+ if isStopLossPriceOrder:
201
+ request['params']['triggers']['price'] = self.parse_to_numeric(self.price_to_precision(symbol, stopLossPrice))
202
+ if isLimitOrder:
203
+ request['params']['order_type'] = 'stop-loss-limit'
204
+ else:
205
+ request['params']['order_type'] = 'stop-loss'
206
+ else:
207
+ request['params']['triggers']['price'] = self.parse_to_numeric(self.price_to_precision(symbol, takeProfitPrice))
208
+ if isLimitOrder:
209
+ request['params']['order_type'] = 'take-profit-limit'
210
+ else:
211
+ request['params']['order_type'] = 'take-profit'
212
+ elif isTrailingAmountOrder or isTrailingPercentOrder or isTrailingLimitAmountOrder or isTrailingLimitPercentOrder:
213
+ request['params']['triggers']['price_type'] = priceType
214
+ if not isLimitOrder and (isTrailingAmountOrder or isTrailingPercentOrder):
215
+ request['params']['order_type'] = 'trailing-stop'
216
+ if isTrailingAmountOrder:
217
+ request['params']['triggers']['price'] = self.parse_to_numeric(trailingAmountString)
218
+ else:
219
+ request['params']['triggers']['price'] = self.parse_to_numeric(trailingPercentString)
220
+ else:
221
+ # trailing limit orders are not conventionally supported because the static limit_price_type param is not available for trailing-stop-limit orders
222
+ request['params']['limit_price_type'] = priceType
223
+ request['params']['order_type'] = 'trailing-stop-limit'
224
+ if isTrailingLimitAmountOrder:
225
+ request['params']['triggers']['price'] = self.parse_to_numeric(trailingLimitAmountString)
226
+ else:
227
+ request['params']['triggers']['price'] = self.parse_to_numeric(trailingLimitPercentString)
228
+ elif method == 'editOrderWs':
229
+ if isPresetStopLoss or isPresetTakeProfit:
230
+ raise NotSupported(self.id + ' editing the stopLoss and takeProfit on existing orders is currently not supported')
231
+ if isStopLossPriceOrder or isTakeProfitPriceOrder:
232
+ if isStopLossPriceOrder:
233
+ request['params']['trigger_price'] = self.parse_to_numeric(self.price_to_precision(symbol, stopLossPrice))
234
+ else:
235
+ request['params']['trigger_price'] = self.parse_to_numeric(self.price_to_precision(symbol, takeProfitPrice))
236
+ elif isTrailingAmountOrder or isTrailingPercentOrder or isTrailingLimitAmountOrder or isTrailingLimitPercentOrder:
237
+ request['params']['trigger_price_type'] = priceType
238
+ if not isLimitOrder and (isTrailingAmountOrder or isTrailingPercentOrder):
239
+ if isTrailingAmountOrder:
240
+ request['params']['trigger_price'] = self.parse_to_numeric(trailingAmountString)
241
+ else:
242
+ request['params']['trigger_price'] = self.parse_to_numeric(trailingPercentString)
243
+ else:
244
+ request['params']['limit_price_type'] = priceType
245
+ if isTrailingLimitAmountOrder:
246
+ request['params']['trigger_price'] = self.parse_to_numeric(trailingLimitAmountString)
247
+ else:
248
+ request['params']['trigger_price'] = self.parse_to_numeric(trailingLimitPercentString)
249
+ params = self.omit(params, ['clientOrderId', 'cost', 'offset', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent'])
250
+ return [request, params]
251
+
130
252
  async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
131
253
  """
254
+ create a trade order
132
255
 
133
- https://docs.kraken.com/api/docs/websocket-v1/addorder
256
+ https://docs.kraken.com/api/docs/websocket-v2/add_order
134
257
 
135
- create a trade order
136
258
  :param str symbol: unified symbol of the market to create an order in
137
259
  :param str type: 'market' or 'limit'
138
260
  :param str side: 'buy' or 'sell'
@@ -144,50 +266,60 @@ class kraken(ccxt.async_support.kraken):
144
266
  await self.load_markets()
145
267
  token = await self.authenticate()
146
268
  market = self.market(symbol)
147
- url = self.urls['api']['ws']['private']
269
+ url = self.urls['api']['ws']['privateV2']
148
270
  requestId = self.request_id()
149
271
  messageHash = requestId
150
272
  request: dict = {
151
- 'event': 'addOrder',
152
- 'token': token,
153
- 'reqid': requestId,
154
- 'ordertype': type,
155
- 'type': side,
156
- 'pair': market['wsId'],
157
- 'volume': self.amount_to_precision(symbol, amount),
273
+ 'method': 'add_order',
274
+ 'params': {
275
+ 'order_type': type,
276
+ 'side': side,
277
+ 'order_qty': self.parse_to_numeric(self.amount_to_precision(symbol, amount)),
278
+ 'symbol': market['symbol'],
279
+ 'token': token,
280
+ },
281
+ 'req_id': requestId,
158
282
  }
159
- request, params = self.orderRequest('createOrderWs', symbol, type, request, amount, price, params)
283
+ request, params = self.order_request_ws('createOrderWs', symbol, type, request, amount, price, params)
160
284
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
161
285
 
162
286
  def handle_create_edit_order(self, client, message):
163
287
  #
164
288
  # createOrder
165
- # {
166
- # "descr": "sell 0.00010000 XBTUSDT @ market",
167
- # "event": "addOrderStatus",
168
- # "reqid": 1,
169
- # "status": "ok",
170
- # "txid": "OAVXZH-XIE54-JCYYDG"
171
- # }
289
+ # {
290
+ # "method": "add_order",
291
+ # "req_id": 1,
292
+ # "result": {
293
+ # "order_id": "OXM2QD-EALR2-YBAVEU"
294
+ # },
295
+ # "success": True,
296
+ # "time_in": "2025-05-13T10:12:13.876173Z",
297
+ # "time_out": "2025-05-13T10:12:13.890137Z"
298
+ # }
299
+ #
172
300
  # editOrder
173
- # {
174
- # "descr": "order edited price = 9000.00000000",
175
- # "event": "editOrderStatus",
176
- # "originaltxid": "O65KZW-J4AW3-VFS74A",
177
- # "reqid": 3,
178
- # "status": "ok",
179
- # "txid": "OTI672-HJFAO-XOIPPK"
180
- # }
301
+ # {
302
+ # "method": "amend_order",
303
+ # "req_id": 1,
304
+ # "result": {
305
+ # "amend_id": "TYDLSQ-OYNYU-3MNRER",
306
+ # "order_id": "OGL7HR-SWFO4-NRQTHO"
307
+ # },
308
+ # "success": True,
309
+ # "time_in": "2025-05-14T13:54:10.840342Z",
310
+ # "time_out": "2025-05-14T13:54:10.855046Z"
311
+ # }
181
312
  #
182
- order = self.parse_order(message)
183
- messageHash = self.safe_value(message, 'reqid')
313
+ result = self.safe_dict(message, 'result', {})
314
+ order = self.parse_order(result)
315
+ messageHash = self.safe_value_2(message, 'reqid', 'req_id')
184
316
  client.resolve(order, messageHash)
185
317
 
186
318
  async def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
187
319
  """
188
320
  edit a trade order
189
321
 
190
- https://docs.kraken.com/api/docs/websocket-v1/editorder
322
+ https://docs.kraken.com/api/docs/websocket-v2/amend_order
191
323
 
192
324
  :param str id: order id
193
325
  :param str symbol: unified symbol of the market to create an order in
@@ -200,20 +332,19 @@ class kraken(ccxt.async_support.kraken):
200
332
  """
201
333
  await self.load_markets()
202
334
  token = await self.authenticate()
203
- market = self.market(symbol)
204
- url = self.urls['api']['ws']['private']
335
+ url = self.urls['api']['ws']['privateV2']
205
336
  requestId = self.request_id()
206
337
  messageHash = requestId
207
338
  request: dict = {
208
- 'event': 'editOrder',
209
- 'token': token,
210
- 'reqid': requestId,
211
- 'orderid': id,
212
- 'pair': market['wsId'],
339
+ 'method': 'amend_order',
340
+ 'params': {
341
+ 'order_id': id,
342
+ 'order_qty': self.parse_to_numeric(self.amount_to_precision(symbol, amount)),
343
+ 'token': token,
344
+ },
345
+ 'req_id': requestId,
213
346
  }
214
- if amount is not None:
215
- request['volume'] = self.amount_to_precision(symbol, amount)
216
- request, params = self.orderRequest('editOrderWs', symbol, type, request, amount, price, params)
347
+ request, params = self.order_request_ws('editOrderWs', symbol, type, request, amount, price, params)
217
348
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
218
349
 
219
350
  async def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}):
@@ -223,20 +354,24 @@ class kraken(ccxt.async_support.kraken):
223
354
 
224
355
  cancel multiple orders
225
356
  :param str[] ids: order ids
226
- :param str symbol: unified market symbol, default is None
357
+ :param str [symbol]: unified market symbol, default is None
227
358
  :param dict [params]: extra parameters specific to the exchange API endpoint
228
359
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
229
360
  """
361
+ if symbol is not None:
362
+ raise NotSupported(self.id + ' cancelOrdersWs() does not support cancelling orders for a specific symbol.')
230
363
  await self.load_markets()
231
364
  token = await self.authenticate()
232
- url = self.urls['api']['ws']['private']
365
+ url = self.urls['api']['ws']['privateV2']
233
366
  requestId = self.request_id()
234
367
  messageHash = requestId
235
368
  request: dict = {
236
- 'event': 'cancelOrder',
237
- 'token': token,
238
- 'reqid': requestId,
239
- 'txid': ids,
369
+ 'method': 'cancel_order',
370
+ 'params': {
371
+ 'order_id': ids,
372
+ 'token': token,
373
+ },
374
+ 'req_id': requestId,
240
375
  }
241
376
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
242
377
 
@@ -247,35 +382,41 @@ class kraken(ccxt.async_support.kraken):
247
382
 
248
383
  cancels an open order
249
384
  :param str id: order id
250
- :param str symbol: unified symbol of the market the order was made in
385
+ :param str [symbol]: unified symbol of the market the order was made in
251
386
  :param dict [params]: extra parameters specific to the exchange API endpoint
252
387
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
253
388
  """
389
+ if symbol is not None:
390
+ raise NotSupported(self.id + ' cancelOrderWs() does not support cancelling orders for a specific symbol.')
254
391
  await self.load_markets()
255
392
  token = await self.authenticate()
256
- url = self.urls['api']['ws']['private']
393
+ url = self.urls['api']['ws']['privateV2']
257
394
  requestId = self.request_id()
258
395
  messageHash = requestId
259
- clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId', id)
260
- params = self.omit(params, ['userref', 'clientOrderId'])
261
396
  request: dict = {
262
- 'event': 'cancelOrder',
263
- 'token': token,
264
- 'reqid': requestId,
265
- 'txid': [clientOrderId],
397
+ 'method': 'cancel_order',
398
+ 'params': {
399
+ 'order_id': [id],
400
+ 'token': token,
401
+ },
402
+ 'req_id': requestId,
266
403
  }
267
404
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
268
405
 
269
406
  def handle_cancel_order(self, client, message):
270
407
  #
271
- # success
272
- # {
273
- # "event": "cancelOrderStatus",
274
- # "status": "ok"
275
- # "reqid": 1,
276
- # }
408
+ # {
409
+ # "method": "cancel_order",
410
+ # "req_id": 123456789,
411
+ # "result": {
412
+ # "order_id": "OKAGJC-YHIWK-WIOZWG"
413
+ # },
414
+ # "success": True,
415
+ # "time_in": "2023-09-21T14:36:57.428972Z",
416
+ # "time_out": "2023-09-21T14:36:57.437952Z"
417
+ # }
277
418
  #
278
- reqId = self.safe_value(message, 'reqid')
419
+ reqId = self.safe_value(message, 'req_id')
279
420
  client.resolve(message, reqId)
280
421
 
281
422
  async def cancel_all_orders_ws(self, symbol: Str = None, params={}):
@@ -284,7 +425,7 @@ class kraken(ccxt.async_support.kraken):
284
425
  https://docs.kraken.com/api/docs/websocket-v1/cancelall
285
426
 
286
427
  cancel all open orders
287
- :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
428
+ :param str [symbol]: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
288
429
  :param dict [params]: extra parameters specific to the exchange API endpoint
289
430
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
290
431
  """
@@ -292,26 +433,32 @@ class kraken(ccxt.async_support.kraken):
292
433
  raise NotSupported(self.id + ' cancelAllOrdersWs() does not support cancelling orders in a specific market.')
293
434
  await self.load_markets()
294
435
  token = await self.authenticate()
295
- url = self.urls['api']['ws']['private']
436
+ url = self.urls['api']['ws']['privateV2']
296
437
  requestId = self.request_id()
297
438
  messageHash = requestId
298
439
  request: dict = {
299
- 'event': 'cancelAll',
300
- 'token': token,
301
- 'reqid': requestId,
440
+ 'method': 'cancel_all',
441
+ 'params': {
442
+ 'token': token,
443
+ },
444
+ 'req_id': requestId,
302
445
  }
303
446
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
304
447
 
305
448
  def handle_cancel_all_orders(self, client, message):
306
449
  #
307
- # {
308
- # "count": 2,
309
- # "event": "cancelAllStatus",
310
- # "status": "ok",
311
- # "reqId": 1
312
- # }
450
+ # {
451
+ # "method": "cancel_all",
452
+ # "req_id": 123456789,
453
+ # "result": {
454
+ # "count": 1
455
+ # },
456
+ # "success": True,
457
+ # "time_in": "2023-09-21T14:36:57.428972Z",
458
+ # "time_out": "2023-09-21T14:36:57.437952Z"
459
+ # }
313
460
  #
314
- reqId = self.safe_value(message, 'reqid')
461
+ reqId = self.safe_value(message, 'req_id')
315
462
  client.resolve(message, reqId)
316
463
 
317
464
  def handle_ticker(self, client, message, subscription):
@@ -870,6 +1017,20 @@ class kraken(ccxt.async_support.kraken):
870
1017
  # "version": "0.2.0"
871
1018
  # }
872
1019
  #
1020
+ # v2
1021
+ # {
1022
+ # channel: 'status',
1023
+ # type: 'update',
1024
+ # data: [
1025
+ # {
1026
+ # version: '2.0.10',
1027
+ # system: 'online',
1028
+ # api_version: 'v2',
1029
+ # connection_id: 6447481662169813000
1030
+ # }
1031
+ # ]
1032
+ # }
1033
+ #
873
1034
  return message
874
1035
 
875
1036
  async def authenticate(self, params={}):
@@ -1460,9 +1621,18 @@ class kraken(ccxt.async_support.kraken):
1460
1621
  # "subscription": {name: "ticker"}
1461
1622
  # }
1462
1623
  #
1463
- errorMessage = self.safe_string(message, 'errorMessage')
1624
+ # v2
1625
+ # {
1626
+ # "error": "Unsupported field: 'price' for the given msg type: add order",
1627
+ # "method": "add_order",
1628
+ # "success": False,
1629
+ # "time_in": "2025-05-13T08:59:44.803511Z",
1630
+ # "time_out": "2025-05-13T08:59:44.803542Z'
1631
+ # }
1632
+ #
1633
+ errorMessage = self.safe_string_2(message, 'errorMessage', 'error')
1464
1634
  if errorMessage is not None:
1465
- requestId = self.safe_value(message, 'reqid')
1635
+ requestId = self.safe_value_2(message, 'reqid', 'req_id')
1466
1636
  if requestId is not None:
1467
1637
  broad = self.exceptions['ws']['broad']
1468
1638
  broadKey = self.find_broadly_matched_key(broad, errorMessage)
@@ -1507,15 +1677,15 @@ class kraken(ccxt.async_support.kraken):
1507
1677
  if method is not None:
1508
1678
  method(client, message)
1509
1679
  if self.handle_error_message(client, message):
1510
- event = self.safe_string(message, 'event')
1680
+ event = self.safe_string_2(message, 'event', 'method')
1511
1681
  methods: dict = {
1512
1682
  'heartbeat': self.handle_heartbeat,
1513
1683
  'systemStatus': self.handle_system_status,
1514
1684
  'subscriptionStatus': self.handle_subscription_status,
1515
- 'addOrderStatus': self.handle_create_edit_order,
1516
- 'editOrderStatus': self.handle_create_edit_order,
1517
- 'cancelOrderStatus': self.handle_cancel_order,
1518
- 'cancelAllStatus': self.handle_cancel_all_orders,
1685
+ 'add_order': self.handle_create_edit_order,
1686
+ 'amend_order': self.handle_create_edit_order,
1687
+ 'cancel_order': self.handle_cancel_order,
1688
+ 'cancel_all': self.handle_cancel_all_orders,
1519
1689
  }
1520
1690
  method = self.safe_value(methods, event)
1521
1691
  if method is not None:
ccxt/pro/luno.py CHANGED
@@ -196,15 +196,16 @@ class luno(ccxt.async_support.luno):
196
196
  timestamp = self.safe_integer(message, 'timestamp')
197
197
  if not (symbol in self.orderbooks):
198
198
  self.orderbooks[symbol] = self.indexed_order_book({})
199
- orderbook = self.orderbooks[symbol]
200
199
  asks = self.safe_value(message, 'asks')
201
200
  if asks is not None:
202
201
  snapshot = self.custom_parse_order_book(message, symbol, timestamp, 'bids', 'asks', 'price', 'volume', 'id')
203
- orderbook.reset(snapshot)
202
+ self.orderbooks[symbol] = self.indexed_order_book(snapshot)
204
203
  else:
205
- self.handle_delta(orderbook, message)
206
- orderbook['timestamp'] = timestamp
207
- orderbook['datetime'] = self.iso8601(timestamp)
204
+ ob = self.orderbooks[symbol]
205
+ self.handle_delta(ob, message)
206
+ ob['timestamp'] = timestamp
207
+ ob['datetime'] = self.iso8601(timestamp)
208
+ orderbook = self.orderbooks[symbol]
208
209
  nonce = self.safe_integer(message, 'sequence')
209
210
  orderbook['nonce'] = nonce
210
211
  client.resolve(orderbook, messageHash)