ccxt 4.4.90__py2.py3-none-any.whl → 4.4.92__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 (71) hide show
  1. ccxt/__init__.py +1 -3
  2. ccxt/abstract/lbank.py +1 -0
  3. ccxt/async_support/__init__.py +1 -3
  4. ccxt/async_support/base/exchange.py +6 -3
  5. ccxt/async_support/base/ws/client.py +173 -64
  6. ccxt/async_support/base/ws/future.py +23 -50
  7. ccxt/async_support/binance.py +1 -1
  8. ccxt/async_support/bitmart.py +7 -0
  9. ccxt/async_support/bitmex.py +2 -1
  10. ccxt/async_support/bitvavo.py +7 -1
  11. ccxt/async_support/cex.py +61 -0
  12. ccxt/async_support/cryptocom.py +17 -2
  13. ccxt/async_support/cryptomus.py +1 -1
  14. ccxt/async_support/exmo.py +25 -10
  15. ccxt/async_support/gate.py +2 -2
  16. ccxt/async_support/htx.py +1 -1
  17. ccxt/async_support/hyperliquid.py +104 -53
  18. ccxt/async_support/kraken.py +26 -1
  19. ccxt/async_support/krakenfutures.py +1 -1
  20. ccxt/async_support/lbank.py +113 -33
  21. ccxt/async_support/mexc.py +1 -0
  22. ccxt/async_support/modetrade.py +2 -2
  23. ccxt/async_support/okx.py +2 -2
  24. ccxt/async_support/paradex.py +1 -1
  25. ccxt/base/exchange.py +22 -23
  26. ccxt/base/types.py +1 -0
  27. ccxt/binance.py +1 -1
  28. ccxt/bitmart.py +7 -0
  29. ccxt/bitmex.py +2 -1
  30. ccxt/bitvavo.py +7 -1
  31. ccxt/cex.py +61 -0
  32. ccxt/cryptocom.py +17 -2
  33. ccxt/cryptomus.py +1 -1
  34. ccxt/exmo.py +24 -10
  35. ccxt/gate.py +2 -2
  36. ccxt/htx.py +1 -1
  37. ccxt/hyperliquid.py +104 -53
  38. ccxt/kraken.py +26 -1
  39. ccxt/krakenfutures.py +1 -1
  40. ccxt/lbank.py +113 -33
  41. ccxt/mexc.py +1 -0
  42. ccxt/modetrade.py +2 -2
  43. ccxt/okx.py +2 -2
  44. ccxt/paradex.py +1 -1
  45. ccxt/pro/__init__.py +1 -1
  46. ccxt/pro/bitstamp.py +1 -1
  47. ccxt/pro/bybit.py +9 -140
  48. ccxt/pro/kraken.py +246 -258
  49. ccxt/pro/mexc.py +0 -1
  50. {ccxt-4.4.90.dist-info → ccxt-4.4.92.dist-info}/METADATA +6 -7
  51. {ccxt-4.4.90.dist-info → ccxt-4.4.92.dist-info}/RECORD +54 -71
  52. ccxt/abstract/coinlist.py +0 -57
  53. ccxt/async_support/base/ws/aiohttp_client.py +0 -147
  54. ccxt/async_support/bitcoincom.py +0 -18
  55. ccxt/async_support/bitfinex1.py +0 -1711
  56. ccxt/async_support/bitpanda.py +0 -17
  57. ccxt/async_support/coinlist.py +0 -2542
  58. ccxt/async_support/poloniexfutures.py +0 -1875
  59. ccxt/bitcoincom.py +0 -18
  60. ccxt/bitfinex1.py +0 -1710
  61. ccxt/bitpanda.py +0 -17
  62. ccxt/coinlist.py +0 -2542
  63. ccxt/poloniexfutures.py +0 -1875
  64. ccxt/pro/bitcoincom.py +0 -35
  65. ccxt/pro/bitfinex1.py +0 -635
  66. ccxt/pro/bitpanda.py +0 -16
  67. ccxt/pro/poloniexfutures.py +0 -1004
  68. ccxt/pro/wazirx.py +0 -766
  69. {ccxt-4.4.90.dist-info → ccxt-4.4.92.dist-info}/LICENSE.txt +0 -0
  70. {ccxt-4.4.90.dist-info → ccxt-4.4.92.dist-info}/WHEEL +0 -0
  71. {ccxt-4.4.90.dist-info → ccxt-4.4.92.dist-info}/top_level.txt +0 -0
ccxt/async_support/cex.py CHANGED
@@ -36,34 +36,95 @@ class cex(Exchange, ImplicitAPI):
36
36
  'swap': False,
37
37
  'future': False,
38
38
  'option': False,
39
+ 'addMargin': False,
40
+ 'borrowCrossMargin': False,
41
+ 'borrowIsolatedMargin': False,
42
+ 'borrowMargin': False,
39
43
  'cancelAllOrders': True,
40
44
  'cancelOrder': True,
45
+ 'closeAllPositions': False,
46
+ 'closePosition': False,
41
47
  'createOrder': True,
48
+ 'createOrderWithTakeProfitAndStopLoss': False,
49
+ 'createOrderWithTakeProfitAndStopLossWs': False,
50
+ 'createPostOnlyOrder': False,
42
51
  'createReduceOnlyOrder': False,
43
52
  'createStopOrder': True,
44
53
  'createTriggerOrder': True,
45
54
  'fetchAccounts': True,
46
55
  'fetchBalance': True,
56
+ 'fetchBorrowInterest': False,
57
+ 'fetchBorrowRate': False,
58
+ 'fetchBorrowRateHistories': False,
59
+ 'fetchBorrowRateHistory': False,
60
+ 'fetchBorrowRates': False,
61
+ 'fetchBorrowRatesPerSymbol': False,
47
62
  'fetchClosedOrder': True,
48
63
  'fetchClosedOrders': True,
64
+ 'fetchCrossBorrowRate': False,
65
+ 'fetchCrossBorrowRates': False,
49
66
  'fetchCurrencies': True,
50
67
  'fetchDepositAddress': True,
51
68
  'fetchDepositsWithdrawals': True,
52
69
  'fetchFundingHistory': False,
70
+ 'fetchFundingInterval': False,
71
+ 'fetchFundingIntervals': False,
53
72
  'fetchFundingRate': False,
54
73
  'fetchFundingRateHistory': False,
55
74
  'fetchFundingRates': False,
75
+ 'fetchGreeks': False,
76
+ 'fetchIndexOHLCV': False,
77
+ 'fetchIsolatedBorrowRate': False,
78
+ 'fetchIsolatedBorrowRates': False,
79
+ 'fetchIsolatedPositions': False,
56
80
  'fetchLedger': True,
81
+ 'fetchLeverage': False,
82
+ 'fetchLeverages': False,
83
+ 'fetchLeverageTiers': False,
84
+ 'fetchLiquidations': False,
85
+ 'fetchLongShortRatio': False,
86
+ 'fetchLongShortRatioHistory': False,
87
+ 'fetchMarginAdjustmentHistory': False,
88
+ 'fetchMarginMode': False,
89
+ 'fetchMarginModes': False,
90
+ 'fetchMarketLeverageTiers': False,
57
91
  'fetchMarkets': True,
92
+ 'fetchMarkOHLCV': False,
93
+ 'fetchMarkPrices': False,
94
+ 'fetchMyLiquidations': False,
95
+ 'fetchMySettlementHistory': False,
58
96
  'fetchOHLCV': True,
97
+ 'fetchOpenInterest': False,
98
+ 'fetchOpenInterestHistory': False,
99
+ 'fetchOpenInterests': False,
59
100
  'fetchOpenOrder': True,
60
101
  'fetchOpenOrders': True,
102
+ 'fetchOption': False,
103
+ 'fetchOptionChain': False,
61
104
  'fetchOrderBook': True,
105
+ 'fetchPosition': False,
106
+ 'fetchPositionHistory': False,
107
+ 'fetchPositionMode': False,
108
+ 'fetchPositions': False,
109
+ 'fetchPositionsForSymbol': False,
110
+ 'fetchPositionsHistory': False,
111
+ 'fetchPositionsRisk': False,
112
+ 'fetchPremiumIndexOHLCV': False,
113
+ 'fetchSettlementHistory': False,
62
114
  'fetchTicker': True,
63
115
  'fetchTickers': True,
64
116
  'fetchTime': True,
65
117
  'fetchTrades': True,
66
118
  'fetchTradingFees': True,
119
+ 'fetchVolatilityHistory': False,
120
+ 'reduceMargin': False,
121
+ 'repayCrossMargin': False,
122
+ 'repayIsolatedMargin': False,
123
+ 'repayMargin': False,
124
+ 'setLeverage': False,
125
+ 'setMargin': False,
126
+ 'setMarginMode': False,
127
+ 'setPositionMode': False,
67
128
  'transfer': True,
68
129
  },
69
130
  'urls': {
@@ -548,7 +548,22 @@ class cryptocom(Exchange, ImplicitAPI):
548
548
  # self endpoint requires authentication
549
549
  if not self.check_required_credentials(False):
550
550
  return None
551
- response = await self.v1PrivatePostPrivateGetCurrencyNetworks(params)
551
+ skipFetchCurrencies = False
552
+ skipFetchCurrencies, params = self.handle_option_and_params(params, 'fetchCurrencies', 'skipFetchCurrencies', False)
553
+ if skipFetchCurrencies:
554
+ # sub-accounts can't access self endpoint
555
+ return None
556
+ response = {}
557
+ try:
558
+ response = await self.v1PrivatePostPrivateGetCurrencyNetworks(params)
559
+ except Exception as e:
560
+ if isinstance(e, ExchangeError):
561
+ # sub-accounts can't access self endpoint
562
+ # {"code":"10001","msg":"SYS_ERROR"}
563
+ return None
564
+ raise e
565
+ # do nothing
566
+ # sub-accounts can't access self endpoint
552
567
  #
553
568
  # {
554
569
  # "id": "1747502328559",
@@ -573,7 +588,7 @@ class cryptocom(Exchange, ImplicitAPI):
573
588
  # "network_id": "CRONOS",
574
589
  # "withdrawal_fee": "0.18000000",
575
590
  # "withdraw_enabled": True,
576
- # "min_withdrawal_amount": "0.36",
591
+ # "min_withdrawal_amount": "0.35",
577
592
  # "deposit_enabled": True,
578
593
  # "confirmation_required": "15"
579
594
  # },
@@ -461,7 +461,7 @@ class cryptomus(Exchange, ImplicitAPI):
461
461
  #
462
462
  # {
463
463
  # "currency_pair": "XMR_USDT",
464
- # "last_price": "158.04829771",
464
+ # "last_price": "158.04829772",
465
465
  # "base_volume": "0.35185785",
466
466
  # "quote_volume": "55.523761128544"
467
467
  # }
@@ -5,6 +5,7 @@
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.exmo import ImplicitAPI
8
+ import asyncio
8
9
  import hashlib
9
10
  from ccxt.base.types import Any, Balances, Currencies, Currency, DepositAddress, Int, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, OrderBooks, Trade, TradingFees, Transaction
10
11
  from typing import List
@@ -666,8 +667,9 @@ class exmo(Exchange, ImplicitAPI):
666
667
  :param dict [params]: extra parameters specific to the exchange API endpoint
667
668
  :returns dict: an associative dictionary of currencies
668
669
  """
670
+ promises = []
669
671
  #
670
- currencyList = await self.publicGetCurrencyListExtended(params)
672
+ promises.append(self.publicGetCurrencyListExtended(params))
671
673
  #
672
674
  # [
673
675
  # {"name":"VLX","description":"Velas"},
@@ -676,7 +678,7 @@ class exmo(Exchange, ImplicitAPI):
676
678
  # {"name":"USD","description":"US Dollar"}
677
679
  # ]
678
680
  #
679
- cryptoList = await self.publicGetPaymentsProvidersCryptoList(params)
681
+ promises.append(self.publicGetPaymentsProvidersCryptoList(params))
680
682
  #
681
683
  # {
682
684
  # "BTC":[
@@ -701,6 +703,9 @@ class exmo(Exchange, ImplicitAPI):
701
703
  # ],
702
704
  # }
703
705
  #
706
+ responses = await asyncio.gather(*promises)
707
+ currencyList = responses[0]
708
+ cryptoList = responses[1]
704
709
  result: dict = {}
705
710
  for i in range(0, len(currencyList)):
706
711
  currency = currencyList[i]
@@ -754,6 +759,10 @@ class exmo(Exchange, ImplicitAPI):
754
759
  commissionDesc = self.safe_string(provider, 'commission_desc')
755
760
  fee = self.parse_fixed_float_value(commissionDesc)
756
761
  code = self.safe_currency_code(currencyId)
762
+ info = {
763
+ 'currency': currency,
764
+ 'providers': providers,
765
+ }
757
766
  result[code] = {
758
767
  'id': currencyId,
759
768
  'code': code,
@@ -765,7 +774,7 @@ class exmo(Exchange, ImplicitAPI):
765
774
  'fee': fee,
766
775
  'precision': self.parse_number('1e-8'),
767
776
  'limits': limits,
768
- 'info': providers,
777
+ 'info': info,
769
778
  'networks': {},
770
779
  }
771
780
  return result
@@ -779,7 +788,8 @@ class exmo(Exchange, ImplicitAPI):
779
788
  :param dict [params]: extra parameters specific to the exchange API endpoint
780
789
  :returns dict[]: an array of objects representing market data
781
790
  """
782
- response = await self.publicGetPairSettings(params)
791
+ promises = []
792
+ promises.append(self.publicGetPairSettings(params))
783
793
  #
784
794
  # {
785
795
  # "BTC_USD":{
@@ -796,8 +806,9 @@ class exmo(Exchange, ImplicitAPI):
796
806
  # }
797
807
  #
798
808
  marginPairsDict: dict = {}
799
- if self.check_required_credentials(False):
800
- marginPairs = await self.privatePostMarginPairList(params)
809
+ fetchMargin = self.check_required_credentials(False)
810
+ if fetchMargin:
811
+ promises.append(self.privatePostMarginPairList(params))
801
812
  #
802
813
  # {
803
814
  # "pairs": [
@@ -827,14 +838,18 @@ class exmo(Exchange, ImplicitAPI):
827
838
  # ]
828
839
  # }
829
840
  #
830
- pairs = self.safe_value(marginPairs, 'pairs')
841
+ responses = await asyncio.gather(*promises)
842
+ spotResponse = responses[0]
843
+ if fetchMargin:
844
+ marginPairs = responses[1]
845
+ pairs = self.safe_list(marginPairs, 'pairs')
831
846
  marginPairsDict = self.index_by(pairs, 'name')
832
- keys = list(response.keys())
847
+ keys = list(spotResponse.keys())
833
848
  result = []
834
849
  for i in range(0, len(keys)):
835
850
  id = keys[i]
836
- market = response[id]
837
- marginMarket = self.safe_value(marginPairsDict, id)
851
+ market = spotResponse[id]
852
+ marginMarket = self.safe_dict(marginPairsDict, id)
838
853
  symbol = id.replace('_', '/')
839
854
  baseId, quoteId = symbol.split('/')
840
855
  base = self.safe_currency_code(baseId)
@@ -1242,7 +1242,7 @@ class gate(Exchange, ImplicitAPI):
1242
1242
  self.fetch_option_markets(params),
1243
1243
  ]
1244
1244
  if not sandboxMode:
1245
- # gate does not have a sandbox for spot markets
1245
+ # gate doesn't have a sandbox for spot markets
1246
1246
  mainnetOnly = [self.fetch_spot_markets(params)]
1247
1247
  rawPromises = self.array_concat(rawPromises, mainnetOnly)
1248
1248
  promises = await asyncio.gather(*rawPromises)
@@ -1653,7 +1653,7 @@ class gate(Exchange, ImplicitAPI):
1653
1653
  'contractSize': self.parse_number('1'),
1654
1654
  'expiry': expiry,
1655
1655
  'expiryDatetime': self.iso8601(expiry),
1656
- 'strike': strike,
1656
+ 'strike': self.parse_number(strike),
1657
1657
  'optionType': optionType,
1658
1658
  'precision': {
1659
1659
  'amount': self.parse_number('1'), # all options have self step size
ccxt/async_support/htx.py CHANGED
@@ -6342,7 +6342,7 @@ class htx(Exchange, ImplicitAPI):
6342
6342
  fee = self.safe_number(params, 'fee')
6343
6343
  if fee is None:
6344
6344
  currencies = await self.fetch_currencies()
6345
- self.currencies = self.deep_extend(self.currencies, currencies)
6345
+ self.currencies = self.map_to_safe_map(self.deep_extend(self.currencies, currencies))
6346
6346
  targetNetwork = self.safe_value(currency['networks'], networkCode, {})
6347
6347
  fee = self.safe_number(targetNetwork, 'fee')
6348
6348
  if fee is None:
@@ -57,6 +57,7 @@ class hyperliquid(Exchange, ImplicitAPI):
57
57
  'createMarketSellOrderWithCost': False,
58
58
  'createOrder': True,
59
59
  'createOrders': True,
60
+ 'createOrderWithTakeProfitAndStopLoss': True,
60
61
  'createReduceOnlyOrder': True,
61
62
  'createStopOrder': True,
62
63
  'createTriggerOrder': True,
@@ -240,7 +241,16 @@ class hyperliquid(Exchange, ImplicitAPI):
240
241
  'triggerDirection': False,
241
242
  'stopLossPrice': False,
242
243
  'takeProfitPrice': False,
243
- 'attachedStopLossTakeProfit': None,
244
+ 'attachedStopLossTakeProfit': {
245
+ 'triggerPriceType': {
246
+ 'last': False,
247
+ 'mark': False,
248
+ 'index': False,
249
+ },
250
+ 'triggerPrice': True,
251
+ 'type': True,
252
+ 'price': True,
253
+ },
244
254
  'timeInForce': {
245
255
  'IOC': True,
246
256
  'FOK': False,
@@ -1404,6 +1414,65 @@ class hyperliquid(Exchange, ImplicitAPI):
1404
1414
  statuses = self.safe_list(data, 'statuses', [])
1405
1415
  return self.parse_orders(statuses, None)
1406
1416
 
1417
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: str, price: Str = None, params={}):
1418
+ market = self.market(symbol)
1419
+ type = type.upper()
1420
+ side = side.upper()
1421
+ isMarket = (type == 'MARKET')
1422
+ isBuy = (side == 'BUY')
1423
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_id')
1424
+ slippage = self.safe_string(params, 'slippage')
1425
+ defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
1426
+ postOnly = self.safe_bool(params, 'postOnly', False)
1427
+ if postOnly:
1428
+ defaultTimeInForce = 'alo'
1429
+ timeInForce = self.safe_string_lower(params, 'timeInForce', defaultTimeInForce)
1430
+ timeInForce = self.capitalize(timeInForce)
1431
+ triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
1432
+ stopLossPrice = self.safe_string(params, 'stopLossPrice', triggerPrice)
1433
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
1434
+ isTrigger = (stopLossPrice or takeProfitPrice)
1435
+ px = None
1436
+ if isMarket:
1437
+ if price is None:
1438
+ raise ArgumentsRequired(self.id + ' market orders require price to calculate the max slippage price. Default slippage can be set in options(default is 5%).')
1439
+ px = Precise.string_mul(price, Precise.string_add('1', slippage)) if (isBuy) else Precise.string_mul(price, Precise.string_sub('1', slippage))
1440
+ px = self.price_to_precision(symbol, px) # round after adding slippage
1441
+ else:
1442
+ px = self.price_to_precision(symbol, price)
1443
+ sz = self.amount_to_precision(symbol, amount)
1444
+ reduceOnly = self.safe_bool(params, 'reduceOnly', False)
1445
+ orderType: dict = {}
1446
+ if isTrigger:
1447
+ isTp = False
1448
+ if takeProfitPrice is not None:
1449
+ triggerPrice = self.price_to_precision(symbol, takeProfitPrice)
1450
+ isTp = True
1451
+ else:
1452
+ triggerPrice = self.price_to_precision(symbol, stopLossPrice)
1453
+ orderType['trigger'] = {
1454
+ 'isMarket': isMarket,
1455
+ 'triggerPx': triggerPrice,
1456
+ 'tpsl': 'tp' if (isTp) else 'sl',
1457
+ }
1458
+ else:
1459
+ orderType['limit'] = {
1460
+ 'tif': timeInForce,
1461
+ }
1462
+ params = self.omit(params, ['clientOrderId', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce', 'client_id', 'reduceOnly', 'postOnly'])
1463
+ orderObj: dict = {
1464
+ 'a': self.parse_to_int(market['baseId']),
1465
+ 'b': isBuy,
1466
+ 'p': px,
1467
+ 's': sz,
1468
+ 'r': reduceOnly,
1469
+ 't': orderType,
1470
+ # 'c': clientOrderId,
1471
+ }
1472
+ if clientOrderId is not None:
1473
+ orderObj['c'] = clientOrderId
1474
+ return orderObj
1475
+
1407
1476
  def create_orders_request(self, orders, params={}) -> dict:
1408
1477
  """
1409
1478
  create a list of trade orders
@@ -1431,77 +1500,59 @@ class hyperliquid(Exchange, ImplicitAPI):
1431
1500
  params = self.omit(params, ['slippage', 'clientOrderId', 'client_id', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce'])
1432
1501
  nonce = self.milliseconds()
1433
1502
  orderReq = []
1503
+ grouping = 'na'
1434
1504
  for i in range(0, len(orders)):
1435
1505
  rawOrder = orders[i]
1436
1506
  marketId = self.safe_string(rawOrder, 'symbol')
1437
1507
  market = self.market(marketId)
1438
1508
  symbol = market['symbol']
1439
1509
  type = self.safe_string_upper(rawOrder, 'type')
1440
- isMarket = (type == 'MARKET')
1441
1510
  side = self.safe_string_upper(rawOrder, 'side')
1442
- isBuy = (side == 'BUY')
1443
1511
  amount = self.safe_string(rawOrder, 'amount')
1444
1512
  price = self.safe_string(rawOrder, 'price')
1445
1513
  orderParams = self.safe_dict(rawOrder, 'params', {})
1446
- clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
1447
1514
  slippage = self.safe_string(orderParams, 'slippage', defaultSlippage)
1448
- defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
1449
- postOnly = self.safe_bool(orderParams, 'postOnly', False)
1450
- if postOnly:
1451
- defaultTimeInForce = 'alo'
1452
- timeInForce = self.safe_string_lower(orderParams, 'timeInForce', defaultTimeInForce)
1453
- timeInForce = self.capitalize(timeInForce)
1454
- triggerPrice = self.safe_string_2(orderParams, 'triggerPrice', 'stopPrice')
1455
- stopLossPrice = self.safe_string(orderParams, 'stopLossPrice', triggerPrice)
1456
- takeProfitPrice = self.safe_string(orderParams, 'takeProfitPrice')
1457
- isTrigger = (stopLossPrice or takeProfitPrice)
1458
- px = None
1459
- if isMarket:
1460
- if price is None:
1461
- raise ArgumentsRequired(self.id + ' market orders require price to calculate the max slippage price. Default slippage can be set in options(default is 5%).')
1462
- px = Precise.string_mul(price, Precise.string_add('1', slippage)) if (isBuy) else Precise.string_mul(price, Precise.string_sub('1', slippage))
1463
- px = self.price_to_precision(symbol, px) # round after adding slippage
1464
- else:
1465
- px = self.price_to_precision(symbol, price)
1466
- sz = self.amount_to_precision(symbol, amount)
1467
- reduceOnly = self.safe_bool(orderParams, 'reduceOnly', False)
1468
- orderType: dict = {}
1515
+ orderParams['slippage'] = slippage
1516
+ stopLoss = self.safe_value(orderParams, 'stopLoss')
1517
+ takeProfit = self.safe_value(orderParams, 'takeProfit')
1518
+ isTrigger = (stopLoss or takeProfit)
1519
+ orderParams = self.omit(orderParams, ['stopLoss', 'takeProfit'])
1520
+ mainOrderObj: dict = self.create_order_request(symbol, type, side, amount, price, orderParams)
1521
+ orderReq.append(mainOrderObj)
1469
1522
  if isTrigger:
1470
- isTp = False
1471
- if takeProfitPrice is not None:
1472
- triggerPrice = self.price_to_precision(symbol, takeProfitPrice)
1473
- isTp = True
1523
+ # grouping opposed orders for sl/tp
1524
+ stopLossOrderTriggerPrice = self.safe_string_n(stopLoss, ['triggerPrice', 'stopPrice'])
1525
+ stopLossOrderType = self.safe_string(stopLoss, 'type')
1526
+ stopLossOrderLimitPrice = self.safe_string_n(stopLoss, ['price', 'stopLossPrice'], stopLossOrderTriggerPrice)
1527
+ takeProfitOrderTriggerPrice = self.safe_string_n(takeProfit, ['triggerPrice', 'stopPrice'])
1528
+ takeProfitOrderType = self.safe_string(takeProfit, 'type')
1529
+ takeProfitOrderLimitPrice = self.safe_string_n(takeProfit, ['price', 'takeProfitPrice'], takeProfitOrderTriggerPrice)
1530
+ grouping = 'normalTpsl'
1531
+ orderParams = self.omit(orderParams, ['stopLoss', 'takeProfit'])
1532
+ triggerOrderSide = ''
1533
+ if side == 'BUY':
1534
+ triggerOrderSide = 'sell'
1474
1535
  else:
1475
- triggerPrice = self.price_to_precision(symbol, stopLossPrice)
1476
- orderType['trigger'] = {
1477
- 'isMarket': isMarket,
1478
- 'triggerPx': triggerPrice,
1479
- 'tpsl': 'tp' if (isTp) else 'sl',
1480
- }
1481
- else:
1482
- orderType['limit'] = {
1483
- 'tif': timeInForce,
1484
- }
1485
- orderParams = self.omit(orderParams, ['clientOrderId', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce', 'client_id', 'reduceOnly', 'postOnly'])
1486
- orderObj: dict = {
1487
- 'a': self.parse_to_int(market['baseId']),
1488
- 'b': isBuy,
1489
- 'p': px,
1490
- 's': sz,
1491
- 'r': reduceOnly,
1492
- 't': orderType,
1493
- # 'c': clientOrderId,
1494
- }
1495
- if clientOrderId is not None:
1496
- orderObj['c'] = clientOrderId
1497
- orderReq.append(orderObj)
1536
+ triggerOrderSide = 'buy'
1537
+ if takeProfit is not None:
1538
+ orderObj: dict = self.create_order_request(symbol, takeProfitOrderType, triggerOrderSide, amount, takeProfitOrderLimitPrice, self.extend(orderParams, {
1539
+ 'takeProfitPrice': takeProfitOrderTriggerPrice,
1540
+ 'reduceOnly': True,
1541
+ }))
1542
+ orderReq.append(orderObj)
1543
+ if stopLoss is not None:
1544
+ orderObj: dict = self.create_order_request(symbol, stopLossOrderType, triggerOrderSide, amount, stopLossOrderLimitPrice, self.extend(orderParams, {
1545
+ 'stopLossPrice': stopLossOrderTriggerPrice,
1546
+ 'reduceOnly': True,
1547
+ }))
1548
+ orderReq.append(orderObj)
1498
1549
  vaultAddress = None
1499
1550
  vaultAddress, params = self.handle_option_and_params(params, 'createOrder', 'vaultAddress')
1500
1551
  vaultAddress = self.format_vault_address(vaultAddress)
1501
1552
  orderAction: dict = {
1502
1553
  'type': 'order',
1503
1554
  'orders': orderReq,
1504
- 'grouping': 'na',
1555
+ 'grouping': grouping,
1505
1556
  # 'brokerCode': 1, # cant
1506
1557
  }
1507
1558
  if vaultAddress is None:
@@ -1366,7 +1366,20 @@ class kraken(Exchange, ImplicitAPI):
1366
1366
  # "maker": False
1367
1367
  # }
1368
1368
  #
1369
+ # watchTrades
1370
+ #
1371
+ # {
1372
+ # "symbol": "BTC/USD",
1373
+ # "side": "buy",
1374
+ # "price": 109601.2,
1375
+ # "qty": 0.04561994,
1376
+ # "ord_type": "market",
1377
+ # "trade_id": 83449369,
1378
+ # "timestamp": "2025-05-27T11:24:03.847761Z"
1379
+ # }
1380
+ #
1369
1381
  timestamp = None
1382
+ datetime = None
1370
1383
  side = None
1371
1384
  type = None
1372
1385
  price = None
@@ -1409,6 +1422,14 @@ class kraken(Exchange, ImplicitAPI):
1409
1422
  'cost': self.safe_string(trade, 'fee'),
1410
1423
  'currency': currency,
1411
1424
  }
1425
+ else:
1426
+ symbol = self.safe_string(trade, 'symbol')
1427
+ datetime = self.safe_string(trade, 'timestamp')
1428
+ id = self.safe_string(trade, 'trade_id')
1429
+ side = self.safe_string(trade, 'side')
1430
+ type = self.safe_string(trade, 'ord_type')
1431
+ price = self.safe_string(trade, 'price')
1432
+ amount = self.safe_string(trade, 'qty')
1412
1433
  if market is not None:
1413
1434
  symbol = market['symbol']
1414
1435
  cost = self.safe_string(trade, 'cost')
@@ -1416,12 +1437,16 @@ class kraken(Exchange, ImplicitAPI):
1416
1437
  takerOrMaker = None
1417
1438
  if maker is not None:
1418
1439
  takerOrMaker = 'maker' if maker else 'taker'
1440
+ if datetime is None:
1441
+ datetime = self.iso8601(timestamp)
1442
+ else:
1443
+ timestamp = self.parse8601(datetime)
1419
1444
  return self.safe_trade({
1420
1445
  'id': id,
1421
1446
  'order': orderId,
1422
1447
  'info': trade,
1423
1448
  'timestamp': timestamp,
1424
- 'datetime': self.iso8601(timestamp),
1449
+ 'datetime': datetime,
1425
1450
  'symbol': symbol,
1426
1451
  'type': type,
1427
1452
  'side': side,
@@ -538,7 +538,7 @@ class krakenfutures(Exchange, ImplicitAPI):
538
538
  'code': code,
539
539
  'precision': None,
540
540
  })
541
- self.currencies = self.deep_extend(currencies, self.currencies)
541
+ self.currencies = self.map_to_safe_map(self.deep_extend(currencies, self.currencies))
542
542
  return result
543
543
 
544
544
  async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook: