ccxt 4.2.38__py2.py3-none-any.whl → 4.2.40__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.

Potentially problematic release.


This version of ccxt might be problematic. Click here for more details.

Files changed (141) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bingx.py +4 -0
  3. ccxt/abstract/coinbase.py +1 -0
  4. ccxt/abstract/coinbasepro.py +1 -0
  5. ccxt/abstract/okx.py +1 -0
  6. ccxt/ascendex.py +31 -27
  7. ccxt/async_support/__init__.py +1 -1
  8. ccxt/async_support/ascendex.py +31 -27
  9. ccxt/async_support/base/exchange.py +19 -7
  10. ccxt/async_support/bigone.py +2 -2
  11. ccxt/async_support/binance.py +478 -188
  12. ccxt/async_support/bingx.py +250 -28
  13. ccxt/async_support/bitfinex.py +3 -3
  14. ccxt/async_support/bitfinex2.py +2 -2
  15. ccxt/async_support/bitget.py +16 -7
  16. ccxt/async_support/bitmart.py +2 -2
  17. ccxt/async_support/bitmex.py +2 -2
  18. ccxt/async_support/bitrue.py +2 -2
  19. ccxt/async_support/bitso.py +19 -3
  20. ccxt/async_support/bitstamp.py +25 -3
  21. ccxt/async_support/bitvavo.py +1 -1
  22. ccxt/async_support/bl3p.py +6 -0
  23. ccxt/async_support/blockchaincom.py +21 -0
  24. ccxt/async_support/blofin.py +2 -2
  25. ccxt/async_support/btcalpha.py +9 -0
  26. ccxt/async_support/btcbox.py +9 -0
  27. ccxt/async_support/btcmarkets.py +19 -0
  28. ccxt/async_support/bybit.py +9 -7
  29. ccxt/async_support/cex.py +1 -1
  30. ccxt/async_support/coinbase.py +20 -9
  31. ccxt/async_support/coinbasepro.py +1 -0
  32. ccxt/async_support/coinex.py +4 -4
  33. ccxt/async_support/coinlist.py +11 -9
  34. ccxt/async_support/coinmetro.py +2 -1
  35. ccxt/async_support/coinone.py +1 -1
  36. ccxt/async_support/delta.py +2 -2
  37. ccxt/async_support/deribit.py +3 -3
  38. ccxt/async_support/digifinex.py +3 -3
  39. ccxt/async_support/exmo.py +2 -2
  40. ccxt/async_support/gate.py +6 -6
  41. ccxt/async_support/hitbtc.py +2 -2
  42. ccxt/async_support/hollaex.py +1 -1
  43. ccxt/async_support/htx.py +3 -3
  44. ccxt/async_support/huobijp.py +1 -1
  45. ccxt/async_support/kraken.py +2 -2
  46. ccxt/async_support/krakenfutures.py +117 -16
  47. ccxt/async_support/kucoin.py +5 -5
  48. ccxt/async_support/kucoinfutures.py +2 -2
  49. ccxt/async_support/latoken.py +1 -1
  50. ccxt/async_support/lbank.py +2 -2
  51. ccxt/async_support/luno.py +2 -2
  52. ccxt/async_support/mexc.py +5 -5
  53. ccxt/async_support/ndax.py +1 -1
  54. ccxt/async_support/novadax.py +1 -1
  55. ccxt/async_support/okcoin.py +2 -2
  56. ccxt/async_support/okx.py +18 -21
  57. ccxt/async_support/paymium.py +2 -2
  58. ccxt/async_support/phemex.py +5 -4
  59. ccxt/async_support/poloniex.py +2 -2
  60. ccxt/async_support/poloniexfutures.py +10 -6
  61. ccxt/async_support/probit.py +1 -1
  62. ccxt/async_support/timex.py +1 -1
  63. ccxt/async_support/upbit.py +1 -1
  64. ccxt/async_support/wavesexchange.py +1 -1
  65. ccxt/async_support/whitebit.py +2 -2
  66. ccxt/async_support/woo.py +4 -4
  67. ccxt/async_support/zonda.py +3 -3
  68. ccxt/base/exchange.py +37 -25
  69. ccxt/bigone.py +2 -2
  70. ccxt/binance.py +478 -188
  71. ccxt/bingx.py +250 -28
  72. ccxt/bitfinex.py +3 -3
  73. ccxt/bitfinex2.py +2 -2
  74. ccxt/bitget.py +16 -7
  75. ccxt/bitmart.py +2 -2
  76. ccxt/bitmex.py +2 -2
  77. ccxt/bitrue.py +2 -2
  78. ccxt/bitso.py +19 -3
  79. ccxt/bitstamp.py +25 -3
  80. ccxt/bitvavo.py +1 -1
  81. ccxt/bl3p.py +6 -0
  82. ccxt/blockchaincom.py +21 -0
  83. ccxt/blofin.py +2 -2
  84. ccxt/btcalpha.py +9 -0
  85. ccxt/btcbox.py +9 -0
  86. ccxt/btcmarkets.py +19 -0
  87. ccxt/bybit.py +9 -7
  88. ccxt/cex.py +1 -1
  89. ccxt/coinbase.py +20 -9
  90. ccxt/coinbasepro.py +1 -0
  91. ccxt/coinex.py +4 -4
  92. ccxt/coinlist.py +11 -9
  93. ccxt/coinmetro.py +2 -1
  94. ccxt/coinone.py +1 -1
  95. ccxt/delta.py +2 -2
  96. ccxt/deribit.py +3 -3
  97. ccxt/digifinex.py +3 -3
  98. ccxt/exmo.py +2 -2
  99. ccxt/gate.py +6 -6
  100. ccxt/hitbtc.py +2 -2
  101. ccxt/hollaex.py +1 -1
  102. ccxt/htx.py +3 -3
  103. ccxt/huobijp.py +1 -1
  104. ccxt/kraken.py +2 -2
  105. ccxt/krakenfutures.py +117 -16
  106. ccxt/kucoin.py +5 -5
  107. ccxt/kucoinfutures.py +2 -2
  108. ccxt/latoken.py +1 -1
  109. ccxt/lbank.py +2 -2
  110. ccxt/luno.py +2 -2
  111. ccxt/mexc.py +5 -5
  112. ccxt/ndax.py +1 -1
  113. ccxt/novadax.py +1 -1
  114. ccxt/okcoin.py +2 -2
  115. ccxt/okx.py +18 -21
  116. ccxt/paymium.py +2 -2
  117. ccxt/phemex.py +5 -4
  118. ccxt/poloniex.py +2 -2
  119. ccxt/poloniexfutures.py +10 -6
  120. ccxt/pro/__init__.py +1 -1
  121. ccxt/pro/bitmart.py +129 -46
  122. ccxt/pro/bitvavo.py +1 -1
  123. ccxt/pro/bybit.py +6 -6
  124. ccxt/pro/cex.py +2 -2
  125. ccxt/pro/coinbase.py +2 -2
  126. ccxt/pro/coinex.py +1 -1
  127. ccxt/pro/lbank.py +1 -1
  128. ccxt/pro/mexc.py +1 -1
  129. ccxt/probit.py +1 -1
  130. ccxt/test/test_async.py +3 -1
  131. ccxt/test/test_sync.py +3 -1
  132. ccxt/timex.py +1 -1
  133. ccxt/upbit.py +1 -1
  134. ccxt/wavesexchange.py +1 -1
  135. ccxt/whitebit.py +2 -2
  136. ccxt/woo.py +4 -4
  137. ccxt/zonda.py +3 -3
  138. {ccxt-4.2.38.dist-info → ccxt-4.2.40.dist-info}/METADATA +4 -4
  139. {ccxt-4.2.38.dist-info → ccxt-4.2.40.dist-info}/RECORD +141 -141
  140. {ccxt-4.2.38.dist-info → ccxt-4.2.40.dist-info}/WHEEL +0 -0
  141. {ccxt-4.2.38.dist-info → ccxt-4.2.40.dist-info}/top_level.txt +0 -0
@@ -2362,7 +2362,7 @@ class binance(Exchange, ImplicitAPI):
2362
2362
  reconstructedDate = '20' + year + '-' + month + '-' + day + 'T00:00:00Z'
2363
2363
  return reconstructedDate
2364
2364
 
2365
- def create_expired_option_market(self, symbol):
2365
+ def create_expired_option_market(self, symbol: str):
2366
2366
  # support expired option contracts
2367
2367
  settle = 'USDT'
2368
2368
  optionParts = symbol.split('-')
@@ -2638,7 +2638,7 @@ class binance(Exchange, ImplicitAPI):
2638
2638
  minPrecision = None
2639
2639
  isWithdrawEnabled = True
2640
2640
  isDepositEnabled = True
2641
- networkList = self.safe_value(entry, 'networkList', [])
2641
+ networkList = self.safe_list(entry, 'networkList', [])
2642
2642
  fees = {}
2643
2643
  fee = None
2644
2644
  for j in range(0, len(networkList)):
@@ -2646,12 +2646,12 @@ class binance(Exchange, ImplicitAPI):
2646
2646
  network = self.safe_string(networkItem, 'network')
2647
2647
  # name = self.safe_string(networkItem, 'name')
2648
2648
  withdrawFee = self.safe_number(networkItem, 'withdrawFee')
2649
- depositEnable = self.safe_value(networkItem, 'depositEnable')
2650
- withdrawEnable = self.safe_value(networkItem, 'withdrawEnable')
2649
+ depositEnable = self.safe_bool(networkItem, 'depositEnable')
2650
+ withdrawEnable = self.safe_bool(networkItem, 'withdrawEnable')
2651
2651
  isDepositEnabled = isDepositEnabled or depositEnable
2652
2652
  isWithdrawEnabled = isWithdrawEnabled or withdrawEnable
2653
2653
  fees[network] = withdrawFee
2654
- isDefault = self.safe_value(networkItem, 'isDefault')
2654
+ isDefault = self.safe_bool(networkItem, 'isDefault')
2655
2655
  if isDefault or (fee is None):
2656
2656
  fee = withdrawFee
2657
2657
  precisionTick = self.safe_string(networkItem, 'withdrawIntegerMultiple')
@@ -2659,7 +2659,7 @@ class binance(Exchange, ImplicitAPI):
2659
2659
  # so, when there is zero instead of i.e. 0.001, then we skip those cases, because we don't know the precision - it might be because of network is suspended or other reasons
2660
2660
  if not Precise.string_eq(precisionTick, '0'):
2661
2661
  minPrecision = precisionTick if (minPrecision is None) else Precise.string_min(minPrecision, precisionTick)
2662
- trading = self.safe_value(entry, 'trading')
2662
+ trading = self.safe_bool(entry, 'trading')
2663
2663
  active = (isWithdrawEnabled and isDepositEnabled and trading)
2664
2664
  maxDecimalPlaces = None
2665
2665
  if minPrecision is not None:
@@ -2691,8 +2691,8 @@ class binance(Exchange, ImplicitAPI):
2691
2691
  :returns dict[]: an array of objects representing market data
2692
2692
  """
2693
2693
  promisesRaw = []
2694
- rawFetchMarkets = self.safe_value(self.options, 'fetchMarkets', ['spot', 'linear', 'inverse'])
2695
- sandboxMode = self.safe_value(self.options, 'sandboxMode', False)
2694
+ rawFetchMarkets = self.safe_list(self.options, 'fetchMarkets', ['spot', 'linear', 'inverse'])
2695
+ sandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
2696
2696
  fetchMarkets = []
2697
2697
  for i in range(0, len(rawFetchMarkets)):
2698
2698
  type = rawFetchMarkets[i]
@@ -2957,7 +2957,7 @@ class binance(Exchange, ImplicitAPI):
2957
2957
  future = True
2958
2958
  settle = self.safe_currency_code(settleId)
2959
2959
  spot = not contract
2960
- filters = self.safe_value(market, 'filters', [])
2960
+ filters = self.safe_list(market, 'filters', [])
2961
2961
  filtersByType = self.index_by(filters, 'filterType')
2962
2962
  status = self.safe_string_2(market, 'status', 'contractStatus')
2963
2963
  contractSize = None
@@ -2977,10 +2977,10 @@ class binance(Exchange, ImplicitAPI):
2977
2977
  linear = settle == quote
2978
2978
  inverse = settle == base
2979
2979
  feesType = 'linear' if linear else 'inverse'
2980
- fees = self.safe_value(self.fees, feesType, {})
2980
+ fees = self.safe_dict(self.fees, feesType, {})
2981
2981
  active = (status == 'TRADING')
2982
2982
  if spot:
2983
- permissions = self.safe_value(market, 'permissions', [])
2983
+ permissions = self.safe_list(market, 'permissions', [])
2984
2984
  for j in range(0, len(permissions)):
2985
2985
  if permissions[j] == 'TRD_GRP_003':
2986
2986
  active = False
@@ -3051,7 +3051,7 @@ class binance(Exchange, ImplicitAPI):
3051
3051
  'created': self.safe_integer(market, 'onboardDate'), # present in inverse & linear apis
3052
3052
  }
3053
3053
  if 'PRICE_FILTER' in filtersByType:
3054
- filter = self.safe_value(filtersByType, 'PRICE_FILTER', {})
3054
+ filter = self.safe_dict(filtersByType, 'PRICE_FILTER', {})
3055
3055
  # PRICE_FILTER reports zero values for maxPrice
3056
3056
  # since they updated filter types in November 2018
3057
3057
  # https://github.com/ccxt/ccxt/issues/4286
@@ -3062,7 +3062,7 @@ class binance(Exchange, ImplicitAPI):
3062
3062
  }
3063
3063
  entry['precision']['price'] = self.precision_from_string(filter['tickSize'])
3064
3064
  if 'LOT_SIZE' in filtersByType:
3065
- filter = self.safe_value(filtersByType, 'LOT_SIZE', {})
3065
+ filter = self.safe_dict(filtersByType, 'LOT_SIZE', {})
3066
3066
  stepSize = self.safe_string(filter, 'stepSize')
3067
3067
  entry['precision']['amount'] = self.precision_from_string(stepSize)
3068
3068
  entry['limits']['amount'] = {
@@ -3070,13 +3070,13 @@ class binance(Exchange, ImplicitAPI):
3070
3070
  'max': self.safe_number(filter, 'maxQty'),
3071
3071
  }
3072
3072
  if 'MARKET_LOT_SIZE' in filtersByType:
3073
- filter = self.safe_value(filtersByType, 'MARKET_LOT_SIZE', {})
3073
+ filter = self.safe_dict(filtersByType, 'MARKET_LOT_SIZE', {})
3074
3074
  entry['limits']['market'] = {
3075
3075
  'min': self.safe_number(filter, 'minQty'),
3076
3076
  'max': self.safe_number(filter, 'maxQty'),
3077
3077
  }
3078
3078
  if ('MIN_NOTIONAL' in filtersByType) or ('NOTIONAL' in filtersByType): # notional added in 12/04/23 to spot testnet
3079
- filter = self.safe_value_2(filtersByType, 'MIN_NOTIONAL', 'NOTIONAL', {})
3079
+ filter = self.safe_dict_2(filtersByType, 'MIN_NOTIONAL', 'NOTIONAL', {})
3080
3080
  entry['limits']['cost']['min'] = self.safe_number_2(filter, 'minNotional', 'notional')
3081
3081
  entry['limits']['cost']['max'] = self.safe_number(filter, 'maxNotional')
3082
3082
  return entry
@@ -3720,7 +3720,7 @@ class binance(Exchange, ImplicitAPI):
3720
3720
  else:
3721
3721
  response = await self.publicGetTicker24hr(self.extend(request, params))
3722
3722
  if isinstance(response, list):
3723
- firstTicker = self.safe_value(response, 0, {})
3723
+ firstTicker = self.safe_dict(response, 0, {})
3724
3724
  return self.parse_ticker(firstTicker, market)
3725
3725
  return self.parse_ticker(response, market)
3726
3726
 
@@ -4627,7 +4627,7 @@ class binance(Exchange, ImplicitAPI):
4627
4627
  #
4628
4628
  return self.parse_order(response, market)
4629
4629
 
4630
- async def edit_order(self, id: str, symbol, type, side, amount=None, price=None, params={}):
4630
+ async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: float = None, price: float = None, params={}):
4631
4631
  """
4632
4632
  edit a trade order
4633
4633
  :see: https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade
@@ -4841,7 +4841,7 @@ class binance(Exchange, ImplicitAPI):
4841
4841
  # "msg": "Quantity greater than max quantity."
4842
4842
  # }
4843
4843
  #
4844
- # createOrder, fetchOpenOrders: portfolio margin linear swap and future
4844
+ # createOrder, fetchOpenOrders, fetchOrder, cancelOrder: portfolio margin linear swap and future
4845
4845
  #
4846
4846
  # {
4847
4847
  # "symbol": "BTCUSDT",
@@ -4864,7 +4864,7 @@ class binance(Exchange, ImplicitAPI):
4864
4864
  # "status": "NEW"
4865
4865
  # }
4866
4866
  #
4867
- # createOrder, fetchOpenOrders: portfolio margin inverse swap and future
4867
+ # createOrder, fetchOpenOrders, fetchOrder, cancelOrder: portfolio margin inverse swap and future
4868
4868
  #
4869
4869
  # {
4870
4870
  # "symbol": "ETHUSD_PERP",
@@ -4930,7 +4930,7 @@ class binance(Exchange, ImplicitAPI):
4930
4930
  # "priceProtect": False
4931
4931
  # }
4932
4932
  #
4933
- # createOrder, cancelAllOrders: portfolio margin spot margin
4933
+ # createOrder, cancelAllOrders, cancelOrder: portfolio margin spot margin
4934
4934
  #
4935
4935
  # {
4936
4936
  # "clientOrderId": "x-R4BD3S82e9ef29d8346440f0b28b86",
@@ -4949,7 +4949,7 @@ class binance(Exchange, ImplicitAPI):
4949
4949
  # "type": "LIMIT"
4950
4950
  # }
4951
4951
  #
4952
- # fetchOpenOrders: portfolio margin spot margin
4952
+ # fetchOpenOrders, fetchOrder: portfolio margin spot margin
4953
4953
  #
4954
4954
  # {
4955
4955
  # "symbol": "BTCUSDT",
@@ -4974,6 +4974,31 @@ class binance(Exchange, ImplicitAPI):
4974
4974
  # "preventedQuantity": null
4975
4975
  # }
4976
4976
  #
4977
+ # cancelOrder: portfolio margin linear and inverse swap conditional
4978
+ #
4979
+ # {
4980
+ # "strategyId": 3733211,
4981
+ # "newClientStrategyId": "x-xcKtGhcuaf166172ed504cd1bc0396",
4982
+ # "strategyType": "STOP",
4983
+ # "strategyStatus": "CANCELED",
4984
+ # "origQty": "0.010",
4985
+ # "price": "35000.00",
4986
+ # "reduceOnly": False,
4987
+ # "side": "BUY",
4988
+ # "positionSide": "BOTH",
4989
+ # "stopPrice": "50000.00", # ignored with trailing orders
4990
+ # "symbol": "BTCUSDT",
4991
+ # "timeInForce": "GTC",
4992
+ # "activatePrice": null, # only return with trailing orders
4993
+ # "priceRate": null, # only return with trailing orders
4994
+ # "bookTime": 1707270098774,
4995
+ # "updateTime": 1707270119261,
4996
+ # "workingType": "CONTRACT_PRICE",
4997
+ # "priceProtect": False,
4998
+ # "goodTillDate": 0,
4999
+ # "selfTradePreventionMode": "NONE"
5000
+ # }
5001
+ #
4977
5002
  code = self.safe_string(order, 'code')
4978
5003
  if code is not None:
4979
5004
  # cancelOrders/createOrders might have a partial success
@@ -5004,7 +5029,7 @@ class binance(Exchange, ImplicitAPI):
5004
5029
  cost = self.safe_string(order, 'cumBase', cost)
5005
5030
  type = self.safe_string_lower(order, 'type')
5006
5031
  side = self.safe_string_lower(order, 'side')
5007
- fills = self.safe_value(order, 'fills', [])
5032
+ fills = self.safe_list(order, 'fills', [])
5008
5033
  timeInForce = self.safe_string(order, 'timeInForce')
5009
5034
  if timeInForce == 'GTX':
5010
5035
  # GTX means "Good Till Crossing" and is an equivalent way of saying Post Only
@@ -5034,7 +5059,7 @@ class binance(Exchange, ImplicitAPI):
5034
5059
  'type': type,
5035
5060
  'timeInForce': timeInForce,
5036
5061
  'postOnly': postOnly,
5037
- 'reduceOnly': self.safe_value(order, 'reduceOnly'),
5062
+ 'reduceOnly': self.safe_bool(order, 'reduceOnly'),
5038
5063
  'side': side,
5039
5064
  'price': price,
5040
5065
  'triggerPrice': stopPrice,
@@ -5066,7 +5091,7 @@ class binance(Exchange, ImplicitAPI):
5066
5091
  side = self.safe_string(rawOrder, 'side')
5067
5092
  amount = self.safe_value(rawOrder, 'amount')
5068
5093
  price = self.safe_value(rawOrder, 'price')
5069
- orderParams = self.safe_value(rawOrder, 'params', {})
5094
+ orderParams = self.safe_dict(rawOrder, 'params', {})
5070
5095
  orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
5071
5096
  ordersRequests.append(orderRequest)
5072
5097
  orderSymbols = self.market_symbols(orderSymbols, None, False, True, True)
@@ -5417,7 +5442,7 @@ class binance(Exchange, ImplicitAPI):
5417
5442
  requestParams = self.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'quoteOrderQty', 'cost', 'test'])
5418
5443
  return self.extend(request, requestParams)
5419
5444
 
5420
- async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost, params={}):
5445
+ async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
5421
5446
  """
5422
5447
  create a market order by providing the symbol, side and cost
5423
5448
  :see: https://binance-docs.github.io/apidocs/spot/en/#new-order-trade
@@ -5434,7 +5459,7 @@ class binance(Exchange, ImplicitAPI):
5434
5459
  params['quoteOrderQty'] = cost
5435
5460
  return await self.create_order(symbol, 'market', side, cost, None, params)
5436
5461
 
5437
- async def create_market_buy_order_with_cost(self, symbol: str, cost, params={}):
5462
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
5438
5463
  """
5439
5464
  create a market buy order by providing the symbol and cost
5440
5465
  :see: https://binance-docs.github.io/apidocs/spot/en/#new-order-trade
@@ -5450,7 +5475,7 @@ class binance(Exchange, ImplicitAPI):
5450
5475
  params['quoteOrderQty'] = cost
5451
5476
  return await self.create_order(symbol, 'market', 'buy', cost, None, params)
5452
5477
 
5453
- async def create_market_sell_order_with_cost(self, symbol: str, cost, params={}):
5478
+ async def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}):
5454
5479
  """
5455
5480
  create a market sell order by providing the symbol and cost
5456
5481
  :see: https://binance-docs.github.io/apidocs/spot/en/#new-order-trade
@@ -5474,9 +5499,14 @@ class binance(Exchange, ImplicitAPI):
5474
5499
  :see: https://binance-docs.github.io/apidocs/delivery/en/#query-order-user_data
5475
5500
  :see: https://binance-docs.github.io/apidocs/voptions/en/#query-single-order-trade
5476
5501
  :see: https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-order-user_data
5502
+ :see: https://binance-docs.github.io/apidocs/pm/en/#query-um-order-user_data
5503
+ :see: https://binance-docs.github.io/apidocs/pm/en/#query-cm-order-user_data
5504
+ :see: https://binance-docs.github.io/apidocs/pm/en/#query-margin-account-order-user_data
5505
+ :param str id: the order id
5477
5506
  :param str symbol: unified symbol of the market the order was made in
5478
5507
  :param dict [params]: extra parameters specific to the exchange API endpoint
5479
5508
  :param str [params.marginMode]: 'cross' or 'isolated', for spot margin trading
5509
+ :param boolean [params.portfolioMargin]: set to True if you would like to fetch an order in a portfolio margin account
5480
5510
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
5481
5511
  """
5482
5512
  if symbol is None:
@@ -5485,11 +5515,14 @@ class binance(Exchange, ImplicitAPI):
5485
5515
  market = self.market(symbol)
5486
5516
  defaultType = self.safe_string_2(self.options, 'fetchOrder', 'defaultType', 'spot')
5487
5517
  type = self.safe_string(params, 'type', defaultType)
5488
- marginMode, query = self.handle_margin_mode_and_params('fetchOrder', params)
5518
+ marginMode = None
5519
+ marginMode, params = self.handle_margin_mode_and_params('fetchOrder', params)
5520
+ isPortfolioMargin = None
5521
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'fetchOrder', 'papi', 'portfolioMargin', False)
5489
5522
  request = {
5490
5523
  'symbol': market['id'],
5491
5524
  }
5492
- clientOrderId = self.safe_value_2(params, 'origClientOrderId', 'clientOrderId')
5525
+ clientOrderId = self.safe_string_2(params, 'origClientOrderId', 'clientOrderId')
5493
5526
  if clientOrderId is not None:
5494
5527
  if market['option']:
5495
5528
  request['clientOrderId'] = clientOrderId
@@ -5497,20 +5530,29 @@ class binance(Exchange, ImplicitAPI):
5497
5530
  request['origClientOrderId'] = clientOrderId
5498
5531
  else:
5499
5532
  request['orderId'] = id
5500
- requestParams = self.omit(query, ['type', 'clientOrderId', 'origClientOrderId'])
5533
+ params = self.omit(params, ['type', 'clientOrderId', 'origClientOrderId'])
5501
5534
  response = None
5502
5535
  if market['option']:
5503
- response = await self.eapiPrivateGetOrder(self.extend(request, requestParams))
5536
+ response = await self.eapiPrivateGetOrder(self.extend(request, params))
5504
5537
  elif market['linear']:
5505
- response = await self.fapiPrivateGetOrder(self.extend(request, requestParams))
5538
+ if isPortfolioMargin:
5539
+ response = await self.papiGetUmOrder(self.extend(request, params))
5540
+ else:
5541
+ response = await self.fapiPrivateGetOrder(self.extend(request, params))
5506
5542
  elif market['inverse']:
5507
- response = await self.dapiPrivateGetOrder(self.extend(request, requestParams))
5508
- elif type == 'margin' or marginMode is not None:
5509
- if marginMode == 'isolated':
5510
- request['isIsolated'] = True
5511
- response = await self.sapiGetMarginOrder(self.extend(request, requestParams))
5543
+ if isPortfolioMargin:
5544
+ response = await self.papiGetCmOrder(self.extend(request, params))
5545
+ else:
5546
+ response = await self.dapiPrivateGetOrder(self.extend(request, params))
5547
+ elif (type == 'margin') or (marginMode is not None) or isPortfolioMargin:
5548
+ if isPortfolioMargin:
5549
+ response = await self.papiGetMarginOrder(self.extend(request, params))
5550
+ else:
5551
+ if marginMode == 'isolated':
5552
+ request['isIsolated'] = True
5553
+ response = await self.sapiGetMarginOrder(self.extend(request, params))
5512
5554
  else:
5513
- response = await self.privateGetOrder(self.extend(request, requestParams))
5555
+ response = await self.privateGetOrder(self.extend(request, params))
5514
5556
  return self.parse_order(response, market)
5515
5557
 
5516
5558
  async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
@@ -5779,9 +5821,16 @@ class binance(Exchange, ImplicitAPI):
5779
5821
  :see: https://binance-docs.github.io/apidocs/delivery/en/#cancel-order-trade
5780
5822
  :see: https://binance-docs.github.io/apidocs/voptions/en/#cancel-option-order-trade
5781
5823
  :see: https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-order-trade
5824
+ :see: https://binance-docs.github.io/apidocs/pm/en/#cancel-um-order-trade
5825
+ :see: https://binance-docs.github.io/apidocs/pm/en/#cancel-cm-order-trade
5826
+ :see: https://binance-docs.github.io/apidocs/pm/en/#cancel-um-conditional-order-trade
5827
+ :see: https://binance-docs.github.io/apidocs/pm/en/#cancel-cm-conditional-order-trade
5828
+ :see: https://binance-docs.github.io/apidocs/pm/en/#cancel-margin-account-order-trade
5782
5829
  :param str id: order id
5783
5830
  :param str symbol: unified symbol of the market the order was made in
5784
5831
  :param dict [params]: extra parameters specific to the exchange API endpoint
5832
+ :param boolean [params.portfolioMargin]: set to True if you would like to cancel an order in a portfolio margin account
5833
+ :param boolean [params.stop]: set to True if you would like to cancel a portfolio margin account conditional order
5785
5834
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
5786
5835
  """
5787
5836
  if symbol is None:
@@ -5790,34 +5839,57 @@ class binance(Exchange, ImplicitAPI):
5790
5839
  market = self.market(symbol)
5791
5840
  defaultType = self.safe_string_2(self.options, 'cancelOrder', 'defaultType', 'spot')
5792
5841
  type = self.safe_string(params, 'type', defaultType)
5793
- marginMode, query = self.handle_margin_mode_and_params('cancelOrder', params)
5842
+ marginMode = None
5843
+ marginMode, params = self.handle_margin_mode_and_params('cancelOrder', params)
5844
+ isPortfolioMargin = None
5845
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'cancelOrder', 'papi', 'portfolioMargin', False)
5846
+ isConditional = self.safe_bool_2(params, 'stop', 'conditional')
5794
5847
  request = {
5795
5848
  'symbol': market['id'],
5796
- # 'orderId': id,
5797
- # 'origClientOrderId': id,
5798
5849
  }
5799
- clientOrderId = self.safe_value_2(params, 'origClientOrderId', 'clientOrderId')
5850
+ clientOrderId = self.safe_string_n(params, ['origClientOrderId', 'clientOrderId', 'newClientStrategyId'])
5800
5851
  if clientOrderId is not None:
5801
5852
  if market['option']:
5802
5853
  request['clientOrderId'] = clientOrderId
5803
5854
  else:
5804
- request['origClientOrderId'] = clientOrderId
5855
+ if isPortfolioMargin and isConditional:
5856
+ request['newClientStrategyId'] = clientOrderId
5857
+ else:
5858
+ request['origClientOrderId'] = clientOrderId
5805
5859
  else:
5806
- request['orderId'] = id
5807
- requestParams = self.omit(query, ['type', 'origClientOrderId', 'clientOrderId'])
5860
+ if isPortfolioMargin and isConditional:
5861
+ request['strategyId'] = id
5862
+ else:
5863
+ request['orderId'] = id
5864
+ params = self.omit(params, ['type', 'origClientOrderId', 'clientOrderId', 'newClientStrategyId', 'stop', 'conditional'])
5808
5865
  response = None
5809
5866
  if market['option']:
5810
- response = await self.eapiPrivateDeleteOrder(self.extend(request, requestParams))
5867
+ response = await self.eapiPrivateDeleteOrder(self.extend(request, params))
5811
5868
  elif market['linear']:
5812
- response = await self.fapiPrivateDeleteOrder(self.extend(request, requestParams))
5869
+ if isPortfolioMargin:
5870
+ if isConditional:
5871
+ response = await self.papiDeleteUmConditionalOrder(self.extend(request, params))
5872
+ else:
5873
+ response = await self.papiDeleteUmOrder(self.extend(request, params))
5874
+ else:
5875
+ response = await self.fapiPrivateDeleteOrder(self.extend(request, params))
5813
5876
  elif market['inverse']:
5814
- response = await self.dapiPrivateDeleteOrder(self.extend(request, requestParams))
5815
- elif type == 'margin' or marginMode is not None:
5816
- if marginMode == 'isolated':
5817
- request['isIsolated'] = True
5818
- response = await self.sapiDeleteMarginOrder(self.extend(request, requestParams))
5877
+ if isPortfolioMargin:
5878
+ if isConditional:
5879
+ response = await self.papiDeleteCmConditionalOrder(self.extend(request, params))
5880
+ else:
5881
+ response = await self.papiDeleteCmOrder(self.extend(request, params))
5882
+ else:
5883
+ response = await self.dapiPrivateDeleteOrder(self.extend(request, params))
5884
+ elif (type == 'margin') or (marginMode is not None) or isPortfolioMargin:
5885
+ if isPortfolioMargin:
5886
+ response = await self.papiDeleteMarginOrder(self.extend(request, params))
5887
+ else:
5888
+ if marginMode == 'isolated':
5889
+ request['isIsolated'] = True
5890
+ response = await self.sapiDeleteMarginOrder(self.extend(request, params))
5819
5891
  else:
5820
- response = await self.privateDeleteOrder(self.extend(request, requestParams))
5892
+ response = await self.privateDeleteOrder(self.extend(request, params))
5821
5893
  return self.parse_order(response, market)
5822
5894
 
5823
5895
  async def cancel_all_orders(self, symbol: Str = None, params={}):
@@ -6170,11 +6242,11 @@ class binance(Exchange, ImplicitAPI):
6170
6242
  # },
6171
6243
  # ]
6172
6244
  # }
6173
- results = self.safe_value(response, 'userAssetDribblets', [])
6245
+ results = self.safe_list(response, 'userAssetDribblets', [])
6174
6246
  rows = self.safe_integer(response, 'total', 0)
6175
6247
  data = []
6176
6248
  for i in range(0, rows):
6177
- logs = self.safe_value(results[i], 'userAssetDribbletDetails', [])
6249
+ logs = self.safe_list(results[i], 'userAssetDribbletDetails', [])
6178
6250
  for j in range(0, len(logs)):
6179
6251
  logs[j]['isDustTrade'] = True
6180
6252
  data.append(logs[j])
@@ -6271,7 +6343,7 @@ class binance(Exchange, ImplicitAPI):
6271
6343
  currency = None
6272
6344
  response = None
6273
6345
  request = {}
6274
- legalMoney = self.safe_value(self.options, 'legalMoney', {})
6346
+ legalMoney = self.safe_dict(self.options, 'legalMoney', {})
6275
6347
  fiatOnly = self.safe_bool(params, 'fiat', False)
6276
6348
  params = self.omit(params, 'fiatOnly')
6277
6349
  until = self.safe_integer(params, 'until')
@@ -6370,7 +6442,7 @@ class binance(Exchange, ImplicitAPI):
6370
6442
  paginate, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'paginate')
6371
6443
  if paginate:
6372
6444
  return await self.fetch_paginated_call_dynamic('fetchWithdrawals', code, since, limit, params)
6373
- legalMoney = self.safe_value(self.options, 'legalMoney', {})
6445
+ legalMoney = self.safe_dict(self.options, 'legalMoney', {})
6374
6446
  fiatOnly = self.safe_bool(params, 'fiat', False)
6375
6447
  params = self.omit(params, 'fiatOnly')
6376
6448
  request = {}
@@ -6505,7 +6577,7 @@ class binance(Exchange, ImplicitAPI):
6505
6577
  'Refund Failed': 'failed',
6506
6578
  },
6507
6579
  }
6508
- statuses = self.safe_value(statusesByType, type, {})
6580
+ statuses = self.safe_dict(statusesByType, type, {})
6509
6581
  return self.safe_string(statuses, status, status)
6510
6582
 
6511
6583
  def parse_transaction(self, transaction, currency: Currency = None) -> Transaction:
@@ -6662,7 +6734,7 @@ class binance(Exchange, ImplicitAPI):
6662
6734
  type = self.safe_string(transfer, 'type')
6663
6735
  fromAccount = None
6664
6736
  toAccount = None
6665
- accountsById = self.safe_value(self.options, 'accountsById', {})
6737
+ accountsById = self.safe_dict(self.options, 'accountsById', {})
6666
6738
  if type is not None:
6667
6739
  parts = type.split('_')
6668
6740
  fromAccount = self.safe_value(parts, 0)
@@ -6697,23 +6769,19 @@ class binance(Exchange, ImplicitAPI):
6697
6769
  # }
6698
6770
  #
6699
6771
  marketId = self.safe_string(income, 'symbol')
6700
- symbol = self.safe_symbol(marketId, market, None, 'swap')
6701
- amount = self.safe_number(income, 'income')
6702
6772
  currencyId = self.safe_string(income, 'asset')
6703
- code = self.safe_currency_code(currencyId)
6704
- id = self.safe_string(income, 'tranId')
6705
6773
  timestamp = self.safe_integer(income, 'time')
6706
6774
  return {
6707
6775
  'info': income,
6708
- 'symbol': symbol,
6709
- 'code': code,
6776
+ 'symbol': self.safe_symbol(marketId, market, None, 'swap'),
6777
+ 'code': self.safe_currency_code(currencyId),
6710
6778
  'timestamp': timestamp,
6711
6779
  'datetime': self.iso8601(timestamp),
6712
- 'id': id,
6713
- 'amount': amount,
6780
+ 'id': self.safe_string(income, 'tranId'),
6781
+ 'amount': self.safe_number(income, 'income'),
6714
6782
  }
6715
6783
 
6716
- async def transfer(self, code: str, amount: float, fromAccount, toAccount, params={}) -> TransferEntry:
6784
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
6717
6785
  """
6718
6786
  transfer currency internally between wallets on the same account
6719
6787
  :see: https://binance-docs.github.io/apidocs/spot/en/#user-universal-transfer-user_data
@@ -6751,7 +6819,7 @@ class binance(Exchange, ImplicitAPI):
6751
6819
  if toId == 'ISOLATED':
6752
6820
  if symbol is None:
6753
6821
  raise ArgumentsRequired(self.id + ' transfer() requires params["symbol"] when toAccount is ' + toAccount)
6754
- accountsById = self.safe_value(self.options, 'accountsById', {})
6822
+ accountsById = self.safe_dict(self.options, 'accountsById', {})
6755
6823
  fromIsolated = not (fromId in accountsById)
6756
6824
  toIsolated = not (toId in accountsById)
6757
6825
  if fromIsolated and (market is None):
@@ -6824,7 +6892,7 @@ class binance(Exchange, ImplicitAPI):
6824
6892
  defaultTo = 'spot' if (fromAccount == 'future') else 'future'
6825
6893
  toAccount = self.safe_string(params, 'toAccount', defaultTo)
6826
6894
  type = self.safe_string(params, 'type')
6827
- accountsByType = self.safe_value(self.options, 'accountsByType', {})
6895
+ accountsByType = self.safe_dict(self.options, 'accountsByType', {})
6828
6896
  fromId = self.safe_string(accountsByType, fromAccount)
6829
6897
  toId = self.safe_string(accountsByType, toAccount)
6830
6898
  if type is None:
@@ -6862,7 +6930,7 @@ class binance(Exchange, ImplicitAPI):
6862
6930
  # ]
6863
6931
  # }
6864
6932
  #
6865
- rows = self.safe_value(response, 'rows', [])
6933
+ rows = self.safe_list(response, 'rows', [])
6866
6934
  return self.parse_transfers(rows, currency, since, limit)
6867
6935
 
6868
6936
  async def fetch_deposit_address(self, code: str, params={}):
@@ -6879,7 +6947,7 @@ class binance(Exchange, ImplicitAPI):
6879
6947
  'coin': currency['id'],
6880
6948
  # 'network': 'ETH', # 'BSC', 'XMR', you can get network and isDefault in networkList in the response of sapiGetCapitalConfigDetail
6881
6949
  }
6882
- networks = self.safe_value(self.options, 'networks', {})
6950
+ networks = self.safe_dict(self.options, 'networks', {})
6883
6951
  network = self.safe_string_upper(params, 'network') # self line allows the user to specify either ERC20 or ETH
6884
6952
  network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
6885
6953
  if network is not None:
@@ -6905,7 +6973,7 @@ class binance(Exchange, ImplicitAPI):
6905
6973
  url = self.safe_string(response, 'url')
6906
6974
  impliedNetwork = None
6907
6975
  if url is not None:
6908
- reverseNetworks = self.safe_value(self.options, 'reverseNetworks', {})
6976
+ reverseNetworks = self.safe_dict(self.options, 'reverseNetworks', {})
6909
6977
  parts = url.split('/')
6910
6978
  topLevel = self.safe_string(parts, 2)
6911
6979
  if (topLevel == 'blockchair.com') or (topLevel == 'viewblock.io'):
@@ -6918,7 +6986,7 @@ class binance(Exchange, ImplicitAPI):
6918
6986
  'TRX': {'TRC20': 'TRX'},
6919
6987
  })
6920
6988
  if code in impliedNetworks:
6921
- conversion = self.safe_value(impliedNetworks, code, {})
6989
+ conversion = self.safe_dict(impliedNetworks, code, {})
6922
6990
  impliedNetwork = self.safe_string(conversion, impliedNetwork, impliedNetwork)
6923
6991
  tag = self.safe_string(response, 'tag', '')
6924
6992
  if len(tag) == 0:
@@ -6932,7 +7000,7 @@ class binance(Exchange, ImplicitAPI):
6932
7000
  'info': response,
6933
7001
  }
6934
7002
 
6935
- async def fetch_transaction_fees(self, codes=None, params={}):
7003
+ async def fetch_transaction_fees(self, codes: List[str] = None, params={}):
6936
7004
  """
6937
7005
  * @deprecated
6938
7006
  please use fetchDepositWithdrawFees instead
@@ -7029,7 +7097,7 @@ class binance(Exchange, ImplicitAPI):
7029
7097
  entry = response[i]
7030
7098
  currencyId = self.safe_string(entry, 'coin')
7031
7099
  code = self.safe_currency_code(currencyId)
7032
- networkList = self.safe_value(entry, 'networkList', [])
7100
+ networkList = self.safe_list(entry, 'networkList', [])
7033
7101
  withdrawFees[code] = {}
7034
7102
  for j in range(0, len(networkList)):
7035
7103
  networkEntry = networkList[j]
@@ -7138,14 +7206,14 @@ class binance(Exchange, ImplicitAPI):
7138
7206
  # ]
7139
7207
  # }
7140
7208
  #
7141
- networkList = self.safe_value(fee, 'networkList', [])
7209
+ networkList = self.safe_list(fee, 'networkList', [])
7142
7210
  result = self.deposit_withdraw_fee(fee)
7143
7211
  for j in range(0, len(networkList)):
7144
7212
  networkEntry = networkList[j]
7145
7213
  networkId = self.safe_string(networkEntry, 'network')
7146
7214
  networkCode = self.network_id_to_code(networkId)
7147
7215
  withdrawFee = self.safe_number(networkEntry, 'withdrawFee')
7148
- isDefault = self.safe_value(networkEntry, 'isDefault')
7216
+ isDefault = self.safe_bool(networkEntry, 'isDefault')
7149
7217
  if isDefault is True:
7150
7218
  result['withdraw'] = {
7151
7219
  'fee': withdrawFee,
@@ -7188,7 +7256,7 @@ class binance(Exchange, ImplicitAPI):
7188
7256
  }
7189
7257
  if tag is not None:
7190
7258
  request['addressTag'] = tag
7191
- networks = self.safe_value(self.options, 'networks', {})
7259
+ networks = self.safe_dict(self.options, 'networks', {})
7192
7260
  network = self.safe_string_upper(params, 'network') # self line allows the user to specify either ERC20 or ETH
7193
7261
  network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
7194
7262
  if network is not None:
@@ -7274,7 +7342,7 @@ class binance(Exchange, ImplicitAPI):
7274
7342
  #
7275
7343
  data = response
7276
7344
  if isinstance(data, list):
7277
- data = self.safe_value(data, 0, {})
7345
+ data = self.safe_dict(data, 0, {})
7278
7346
  return self.parse_trading_fee(data)
7279
7347
 
7280
7348
  async def fetch_trading_fees(self, params={}):
@@ -7648,8 +7716,8 @@ class binance(Exchange, ImplicitAPI):
7648
7716
  }
7649
7717
 
7650
7718
  def parse_account_positions(self, account):
7651
- positions = self.safe_value(account, 'positions')
7652
- assets = self.safe_value(account, 'assets', [])
7719
+ positions = self.safe_list(account, 'positions')
7720
+ assets = self.safe_list(account, 'assets', [])
7653
7721
  balances = {}
7654
7722
  for i in range(0, len(assets)):
7655
7723
  entry = assets[i]
@@ -7667,18 +7735,22 @@ class binance(Exchange, ImplicitAPI):
7667
7735
  marketId = self.safe_string(position, 'symbol')
7668
7736
  market = self.safe_market(marketId, None, None, 'contract')
7669
7737
  code = market['quote'] if market['linear'] else market['base']
7670
- # sometimes not all the codes are correctly returned...
7671
- if code in balances:
7672
- parsed = self.parse_account_position(self.extend(position, {
7673
- 'crossMargin': balances[code]['crossMargin'],
7674
- 'crossWalletBalance': balances[code]['crossWalletBalance'],
7675
- }), market)
7676
- result.append(parsed)
7738
+ maintenanceMargin = self.safe_string(position, 'maintMargin')
7739
+ # check for maintenance margin so empty positions are not returned
7740
+ if (maintenanceMargin != '0') and (maintenanceMargin != '0.00000000'):
7741
+ # sometimes not all the codes are correctly returned...
7742
+ if code in balances:
7743
+ parsed = self.parse_account_position(self.extend(position, {
7744
+ 'crossMargin': balances[code]['crossMargin'],
7745
+ 'crossWalletBalance': balances[code]['crossWalletBalance'],
7746
+ }), market)
7747
+ result.append(parsed)
7677
7748
  return result
7678
7749
 
7679
7750
  def parse_account_position(self, position, market: Market = None):
7680
7751
  #
7681
7752
  # usdm
7753
+ #
7682
7754
  # {
7683
7755
  # "symbol": "BTCBUSD",
7684
7756
  # "initialMargin": "0",
@@ -7699,6 +7771,7 @@ class binance(Exchange, ImplicitAPI):
7699
7771
  # }
7700
7772
  #
7701
7773
  # coinm
7774
+ #
7702
7775
  # {
7703
7776
  # "symbol": "BTCUSD_210625",
7704
7777
  # "initialMargin": "0.00024393",
@@ -7717,6 +7790,46 @@ class binance(Exchange, ImplicitAPI):
7717
7790
  # "crossWalletBalance": "34",
7718
7791
  # }
7719
7792
  #
7793
+ # linear portfolio margin
7794
+ #
7795
+ # {
7796
+ # "symbol": "CTSIUSDT",
7797
+ # "initialMargin": "0",
7798
+ # "maintMargin": "0",
7799
+ # "unrealizedProfit": "0.00000000",
7800
+ # "positionInitialMargin": "0",
7801
+ # "openOrderInitialMargin": "0",
7802
+ # "leverage": "20",
7803
+ # "entryPrice": "0.0",
7804
+ # "maxNotional": "25000",
7805
+ # "bidNotional": "0",
7806
+ # "askNotional": "0",
7807
+ # "positionSide": "SHORT",
7808
+ # "positionAmt": "0",
7809
+ # "updateTime": 0,
7810
+ # "notional": "0",
7811
+ # "breakEvenPrice": "0.0"
7812
+ # }
7813
+ #
7814
+ # inverse portoflio margin
7815
+ #
7816
+ # {
7817
+ # "symbol": "TRXUSD_PERP",
7818
+ # "initialMargin": "0",
7819
+ # "maintMargin": "0",
7820
+ # "unrealizedProfit": "0.00000000",
7821
+ # "positionInitialMargin": "0",
7822
+ # "openOrderInitialMargin": "0",
7823
+ # "leverage": "20",
7824
+ # "entryPrice": "0.00000000",
7825
+ # "positionSide": "SHORT",
7826
+ # "positionAmt": "0",
7827
+ # "maxQty": "5000000",
7828
+ # "updateTime": 0,
7829
+ # "notionalValue": "0",
7830
+ # "breakEvenPrice": "0.00000000"
7831
+ # }
7832
+ #
7720
7833
  marketId = self.safe_string(position, 'symbol')
7721
7834
  market = self.safe_market(marketId, market, None, 'contract')
7722
7835
  symbol = self.safe_string(market, 'symbol')
@@ -7745,8 +7858,8 @@ class binance(Exchange, ImplicitAPI):
7745
7858
  contractsString = Precise.string_div(entryNotional, contractSizeNew)
7746
7859
  contractsStringAbs = Precise.string_div(Precise.string_add(contractsString, '0.5'), '1', 0)
7747
7860
  contracts = self.parse_number(contractsStringAbs)
7748
- leverageBrackets = self.safe_value(self.options, 'leverageBrackets', {})
7749
- leverageBracket = self.safe_value(leverageBrackets, symbol, [])
7861
+ leverageBrackets = self.safe_dict(self.options, 'leverageBrackets', {})
7862
+ leverageBracket = self.safe_list(leverageBrackets, symbol, [])
7750
7863
  maintenanceMarginPercentageString = None
7751
7864
  for i in range(0, len(leverageBracket)):
7752
7865
  bracket = leverageBracket[i]
@@ -7759,7 +7872,7 @@ class binance(Exchange, ImplicitAPI):
7759
7872
  timestamp = self.safe_integer(position, 'updateTime')
7760
7873
  if timestamp == 0:
7761
7874
  timestamp = None
7762
- isolated = self.safe_value(position, 'isolated')
7875
+ isolated = self.safe_bool(position, 'isolated')
7763
7876
  marginMode = None
7764
7877
  collateralString = None
7765
7878
  walletBalance = None
@@ -7901,11 +8014,45 @@ class binance(Exchange, ImplicitAPI):
7901
8014
  # "isolatedWallet": "0.00268058"
7902
8015
  # }
7903
8016
  #
8017
+ # inverse portfolio margin
8018
+ #
8019
+ # {
8020
+ # "symbol": "ETHUSD_PERP",
8021
+ # "positionAmt": "1",
8022
+ # "entryPrice": "2422.400000007",
8023
+ # "markPrice": "2424.51267823",
8024
+ # "unRealizedProfit": "0.0000036",
8025
+ # "liquidationPrice": "293.57678898",
8026
+ # "leverage": "100",
8027
+ # "positionSide": "LONG",
8028
+ # "updateTime": 1707371941861,
8029
+ # "maxQty": "15",
8030
+ # "notionalValue": "0.00412454",
8031
+ # "breakEvenPrice": "2423.368960034"
8032
+ # }
8033
+ #
8034
+ # linear portfolio margin
8035
+ #
8036
+ # {
8037
+ # "symbol": "BTCUSDT",
8038
+ # "positionAmt": "0.01",
8039
+ # "entryPrice": "44525.0",
8040
+ # "markPrice": "45464.1735922",
8041
+ # "unRealizedProfit": "9.39173592",
8042
+ # "liquidationPrice": "38007.16308568",
8043
+ # "leverage": "100",
8044
+ # "positionSide": "LONG",
8045
+ # "updateTime": 1707371879042,
8046
+ # "maxNotionalValue": "500000.0",
8047
+ # "notional": "454.64173592",
8048
+ # "breakEvenPrice": "44542.81"
8049
+ # }
8050
+ #
7904
8051
  marketId = self.safe_string(position, 'symbol')
7905
8052
  market = self.safe_market(marketId, market, None, 'contract')
7906
8053
  symbol = self.safe_string(market, 'symbol')
7907
- leverageBrackets = self.safe_value(self.options, 'leverageBrackets', {})
7908
- leverageBracket = self.safe_value(leverageBrackets, symbol, [])
8054
+ leverageBrackets = self.safe_dict(self.options, 'leverageBrackets', {})
8055
+ leverageBracket = self.safe_list(leverageBrackets, symbol, [])
7909
8056
  notionalString = self.safe_string_2(position, 'notional', 'notionalValue')
7910
8057
  notionalStringAbs = Precise.string_abs(notionalString)
7911
8058
  maintenanceMarginPercentageString = None
@@ -7938,7 +8085,7 @@ class binance(Exchange, ImplicitAPI):
7938
8085
  linear = ('notional' in position)
7939
8086
  if marginMode == 'cross':
7940
8087
  # calculate collateral
7941
- precision = self.safe_value(market, 'precision', {})
8088
+ precision = self.safe_dict(market, 'precision', {})
7942
8089
  if linear:
7943
8090
  # walletBalance = (liquidationPrice * (±1 + mmp) ± entryPrice) * contracts
7944
8091
  onePlusMaintenanceMarginPercentageString = None
@@ -8032,11 +8179,19 @@ class binance(Exchange, ImplicitAPI):
8032
8179
  query = self.omit(params, 'type')
8033
8180
  subType = None
8034
8181
  subType, params = self.handle_sub_type_and_params('loadLeverageBrackets', None, params, 'linear')
8182
+ isPortfolioMargin = None
8183
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'loadLeverageBrackets', 'papi', 'portfolioMargin', False)
8035
8184
  response = None
8036
8185
  if self.is_linear(type, subType):
8037
- response = await self.fapiPrivateGetLeverageBracket(query)
8186
+ if isPortfolioMargin:
8187
+ response = await self.papiGetUmLeverageBracket(query)
8188
+ else:
8189
+ response = await self.fapiPrivateGetLeverageBracket(query)
8038
8190
  elif self.is_inverse(type, subType):
8039
- response = await self.dapiPrivateV2GetLeverageBracket(query)
8191
+ if isPortfolioMargin:
8192
+ response = await self.papiGetCmLeverageBracket(query)
8193
+ else:
8194
+ response = await self.dapiPrivateV2GetLeverageBracket(query)
8040
8195
  else:
8041
8196
  raise NotSupported(self.id + ' loadLeverageBrackets() supports linear and inverse contracts only')
8042
8197
  self.options['leverageBrackets'] = {}
@@ -8044,7 +8199,7 @@ class binance(Exchange, ImplicitAPI):
8044
8199
  entry = response[i]
8045
8200
  marketId = self.safe_string(entry, 'symbol')
8046
8201
  symbol = self.safe_symbol(marketId, None, None, 'contract')
8047
- brackets = self.safe_value(entry, 'brackets', [])
8202
+ brackets = self.safe_list(entry, 'brackets', [])
8048
8203
  result = []
8049
8204
  for j in range(0, len(brackets)):
8050
8205
  bracket = brackets[j]
@@ -8059,8 +8214,11 @@ class binance(Exchange, ImplicitAPI):
8059
8214
  retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
8060
8215
  :see: https://binance-docs.github.io/apidocs/futures/en/#notional-and-leverage-brackets-user_data
8061
8216
  :see: https://binance-docs.github.io/apidocs/delivery/en/#notional-bracket-for-symbol-user_data
8217
+ :see: https://binance-docs.github.io/apidocs/pm/en/#um-notional-and-leverage-brackets-user_data
8218
+ :see: https://binance-docs.github.io/apidocs/pm/en/#cm-notional-and-leverage-brackets-user_data
8062
8219
  :param str[]|None symbols: list of unified market symbols
8063
8220
  :param dict [params]: extra parameters specific to the exchange API endpoint
8221
+ :param boolean [params.portfolioMargin]: set to True if you would like to fetch the leverage tiers for a portfolio margin account
8064
8222
  :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
8065
8223
  """
8066
8224
  await self.load_markets()
@@ -8068,11 +8226,19 @@ class binance(Exchange, ImplicitAPI):
8068
8226
  type, params = self.handle_market_type_and_params('fetchLeverageTiers', None, params)
8069
8227
  subType = None
8070
8228
  subType, params = self.handle_sub_type_and_params('fetchLeverageTiers', None, params, 'linear')
8229
+ isPortfolioMargin = None
8230
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'fetchLeverageTiers', 'papi', 'portfolioMargin', False)
8071
8231
  response = None
8072
8232
  if self.is_linear(type, subType):
8073
- response = await self.fapiPrivateGetLeverageBracket(params)
8233
+ if isPortfolioMargin:
8234
+ response = await self.papiGetUmLeverageBracket(params)
8235
+ else:
8236
+ response = await self.fapiPrivateGetLeverageBracket(params)
8074
8237
  elif self.is_inverse(type, subType):
8075
- response = await self.dapiPrivateV2GetLeverageBracket(params)
8238
+ if isPortfolioMargin:
8239
+ response = await self.papiGetCmLeverageBracket(params)
8240
+ else:
8241
+ response = await self.dapiPrivateV2GetLeverageBracket(params)
8076
8242
  else:
8077
8243
  raise NotSupported(self.id + ' fetchLeverageTiers() supports linear and inverse contracts only')
8078
8244
  #
@@ -8139,7 +8305,7 @@ class binance(Exchange, ImplicitAPI):
8139
8305
  #
8140
8306
  marketId = self.safe_string(info, 'symbol')
8141
8307
  market = self.safe_market(marketId, market, None, 'contract')
8142
- brackets = self.safe_value(info, 'brackets', [])
8308
+ brackets = self.safe_list(info, 'brackets', [])
8143
8309
  tiers = []
8144
8310
  for j in range(0, len(brackets)):
8145
8311
  bracket = brackets[j]
@@ -8334,8 +8500,11 @@ class binance(Exchange, ImplicitAPI):
8334
8500
  fetch account positions
8335
8501
  :see: https://binance-docs.github.io/apidocs/futures/en/#account-information-v2-user_data
8336
8502
  :see: https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data
8503
+ :see: https://binance-docs.github.io/apidocs/pm/en/#get-um-account-detail-user_data
8504
+ :see: https://binance-docs.github.io/apidocs/pm/en/#get-cm-account-detail-user_data
8337
8505
  :param str[]|None symbols: list of unified market symbols
8338
8506
  :param dict [params]: extra parameters specific to the exchange API endpoint
8507
+ :param boolean [params.portfolioMargin]: set to True if you would like to fetch positions in a portfolio margin account
8339
8508
  :returns dict: data on account positions
8340
8509
  """
8341
8510
  if symbols is not None:
@@ -8345,14 +8514,22 @@ class binance(Exchange, ImplicitAPI):
8345
8514
  await self.load_leverage_brackets(False, params)
8346
8515
  defaultType = self.safe_string(self.options, 'defaultType', 'future')
8347
8516
  type = self.safe_string(params, 'type', defaultType)
8348
- query = self.omit(params, 'type')
8517
+ params = self.omit(params, 'type')
8349
8518
  subType = None
8350
- subType, query = self.handle_sub_type_and_params('fetchAccountPositions', None, params, 'linear')
8519
+ subType, params = self.handle_sub_type_and_params('fetchAccountPositions', None, params, 'linear')
8520
+ isPortfolioMargin = None
8521
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'fetchAccountPositions', 'papi', 'portfolioMargin', False)
8351
8522
  response = None
8352
8523
  if self.is_linear(type, subType):
8353
- response = await self.fapiPrivateV2GetAccount(query)
8524
+ if isPortfolioMargin:
8525
+ response = await self.papiGetUmAccount(params)
8526
+ else:
8527
+ response = await self.fapiPrivateV2GetAccount(params)
8354
8528
  elif self.is_inverse(type, subType):
8355
- response = await self.dapiPrivateGetAccount(query)
8529
+ if isPortfolioMargin:
8530
+ response = await self.papiGetCmAccount(params)
8531
+ else:
8532
+ response = await self.dapiPrivateGetAccount(params)
8356
8533
  else:
8357
8534
  raise NotSupported(self.id + ' fetchPositions() supports linear and inverse contracts only')
8358
8535
  result = self.parse_account_positions(response)
@@ -8365,8 +8542,11 @@ class binance(Exchange, ImplicitAPI):
8365
8542
  fetch positions risk
8366
8543
  :see: https://binance-docs.github.io/apidocs/futures/en/#position-information-v2-user_data
8367
8544
  :see: https://binance-docs.github.io/apidocs/delivery/en/#position-information-user_data
8545
+ :see: https://binance-docs.github.io/apidocs/pm/en/#query-um-position-information-user_data
8546
+ :see: https://binance-docs.github.io/apidocs/pm/en/#query-cm-position-information-user_data
8368
8547
  :param str[]|None symbols: list of unified market symbols
8369
8548
  :param dict [params]: extra parameters specific to the exchange API endpoint
8549
+ :param boolean [params.portfolioMargin]: set to True if you would like to fetch positions for a portfolio margin account
8370
8550
  :returns dict: data on the positions risk
8371
8551
  """
8372
8552
  if symbols is not None:
@@ -8380,68 +8560,117 @@ class binance(Exchange, ImplicitAPI):
8380
8560
  type = self.safe_string(params, 'type', defaultType)
8381
8561
  subType = None
8382
8562
  subType, params = self.handle_sub_type_and_params('fetchPositionsRisk', None, params, 'linear')
8563
+ isPortfolioMargin = None
8564
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'fetchPositionsRisk', 'papi', 'portfolioMargin', False)
8383
8565
  params = self.omit(params, 'type')
8384
8566
  response = None
8385
8567
  if self.is_linear(type, subType):
8386
- response = await self.fapiPrivateV2GetPositionRisk(self.extend(request, params))
8387
- # ### Response examples ###
8388
- #
8389
- # For One-way position mode:
8390
- # [
8391
- # {
8392
- # "entryPrice": "0.00000",
8393
- # "marginType": "isolated",
8394
- # "isAutoAddMargin": "false",
8395
- # "isolatedMargin": "0.00000000",
8396
- # "leverage": "10",
8397
- # "liquidationPrice": "0",
8398
- # "markPrice": "6679.50671178",
8399
- # "maxNotionalValue": "20000000",
8400
- # "positionAmt": "0.000",
8401
- # "symbol": "BTCUSDT",
8402
- # "unRealizedProfit": "0.00000000",
8403
- # "positionSide": "BOTH",
8404
- # "updateTime": 0
8405
- # }
8406
- # ]
8407
- #
8408
- # For Hedge position mode:
8409
- # [
8410
- # {
8411
- # "entryPrice": "6563.66500",
8412
- # "marginType": "isolated",
8413
- # "isAutoAddMargin": "false",
8414
- # "isolatedMargin": "15517.54150468",
8415
- # "leverage": "10",
8416
- # "liquidationPrice": "5930.78",
8417
- # "markPrice": "6679.50671178",
8418
- # "maxNotionalValue": "20000000",
8419
- # "positionAmt": "20.000",
8420
- # "symbol": "BTCUSDT",
8421
- # "unRealizedProfit": "2316.83423560"
8422
- # "positionSide": "LONG",
8423
- # "updateTime": 1625474304765
8424
- # },
8425
- # {
8426
- # "entryPrice": "0.00000",
8427
- # "marginType": "isolated",
8428
- # "isAutoAddMargin": "false",
8429
- # "isolatedMargin": "5413.95799991",
8430
- # "leverage": "10",
8431
- # "liquidationPrice": "7189.95",
8432
- # "markPrice": "6679.50671178",
8433
- # "maxNotionalValue": "20000000",
8434
- # "positionAmt": "-10.000",
8435
- # "symbol": "BTCUSDT",
8436
- # "unRealizedProfit": "-1156.46711780",
8437
- # "positionSide": "SHORT",
8438
- # "updateTime": 0
8439
- # }
8440
- # ]
8568
+ if isPortfolioMargin:
8569
+ response = await self.papiGetUmPositionRisk(self.extend(request, params))
8570
+ else:
8571
+ response = await self.fapiPrivateV2GetPositionRisk(self.extend(request, params))
8441
8572
  elif self.is_inverse(type, subType):
8442
- response = await self.dapiPrivateGetPositionRisk(self.extend(request, params))
8573
+ if isPortfolioMargin:
8574
+ response = await self.papiGetCmPositionRisk(self.extend(request, params))
8575
+ else:
8576
+ response = await self.dapiPrivateGetPositionRisk(self.extend(request, params))
8443
8577
  else:
8444
8578
  raise NotSupported(self.id + ' fetchPositionsRisk() supports linear and inverse contracts only')
8579
+ # ### Response examples ###
8580
+ #
8581
+ # For One-way position mode:
8582
+ #
8583
+ # [
8584
+ # {
8585
+ # "entryPrice": "0.00000",
8586
+ # "marginType": "isolated",
8587
+ # "isAutoAddMargin": "false",
8588
+ # "isolatedMargin": "0.00000000",
8589
+ # "leverage": "10",
8590
+ # "liquidationPrice": "0",
8591
+ # "markPrice": "6679.50671178",
8592
+ # "maxNotionalValue": "20000000",
8593
+ # "positionAmt": "0.000",
8594
+ # "symbol": "BTCUSDT",
8595
+ # "unRealizedProfit": "0.00000000",
8596
+ # "positionSide": "BOTH",
8597
+ # "updateTime": 0
8598
+ # }
8599
+ # ]
8600
+ #
8601
+ # For Hedge position mode:
8602
+ #
8603
+ # [
8604
+ # {
8605
+ # "entryPrice": "6563.66500",
8606
+ # "marginType": "isolated",
8607
+ # "isAutoAddMargin": "false",
8608
+ # "isolatedMargin": "15517.54150468",
8609
+ # "leverage": "10",
8610
+ # "liquidationPrice": "5930.78",
8611
+ # "markPrice": "6679.50671178",
8612
+ # "maxNotionalValue": "20000000",
8613
+ # "positionAmt": "20.000",
8614
+ # "symbol": "BTCUSDT",
8615
+ # "unRealizedProfit": "2316.83423560"
8616
+ # "positionSide": "LONG",
8617
+ # "updateTime": 1625474304765
8618
+ # },
8619
+ # {
8620
+ # "entryPrice": "0.00000",
8621
+ # "marginType": "isolated",
8622
+ # "isAutoAddMargin": "false",
8623
+ # "isolatedMargin": "5413.95799991",
8624
+ # "leverage": "10",
8625
+ # "liquidationPrice": "7189.95",
8626
+ # "markPrice": "6679.50671178",
8627
+ # "maxNotionalValue": "20000000",
8628
+ # "positionAmt": "-10.000",
8629
+ # "symbol": "BTCUSDT",
8630
+ # "unRealizedProfit": "-1156.46711780",
8631
+ # "positionSide": "SHORT",
8632
+ # "updateTime": 0
8633
+ # }
8634
+ # ]
8635
+ #
8636
+ # inverse portfolio margin:
8637
+ #
8638
+ # [
8639
+ # {
8640
+ # "symbol": "ETHUSD_PERP",
8641
+ # "positionAmt": "1",
8642
+ # "entryPrice": "2422.400000007",
8643
+ # "markPrice": "2424.51267823",
8644
+ # "unRealizedProfit": "0.0000036",
8645
+ # "liquidationPrice": "293.57678898",
8646
+ # "leverage": "100",
8647
+ # "positionSide": "LONG",
8648
+ # "updateTime": 1707371941861,
8649
+ # "maxQty": "15",
8650
+ # "notionalValue": "0.00412454",
8651
+ # "breakEvenPrice": "2423.368960034"
8652
+ # }
8653
+ # ]
8654
+ #
8655
+ # linear portfolio margin:
8656
+ #
8657
+ # [
8658
+ # {
8659
+ # "symbol": "BTCUSDT",
8660
+ # "positionAmt": "0.01",
8661
+ # "entryPrice": "44525.0",
8662
+ # "markPrice": "45464.1735922",
8663
+ # "unRealizedProfit": "9.39173592",
8664
+ # "liquidationPrice": "38007.16308568",
8665
+ # "leverage": "100",
8666
+ # "positionSide": "LONG",
8667
+ # "updateTime": 1707371879042,
8668
+ # "maxNotionalValue": "500000.0",
8669
+ # "notional": "454.64173592",
8670
+ # "breakEvenPrice": "44542.81"
8671
+ # }
8672
+ # ]
8673
+ #
8445
8674
  result = []
8446
8675
  for i in range(0, len(response)):
8447
8676
  parsed = self.parse_position_risk(response[i])
@@ -8454,10 +8683,14 @@ class binance(Exchange, ImplicitAPI):
8454
8683
  fetch the history of funding payments paid and received on self account
8455
8684
  :see: https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data
8456
8685
  :see: https://binance-docs.github.io/apidocs/delivery/en/#get-income-history-user_data
8686
+ :see: https://binance-docs.github.io/apidocs/pm/en/#get-um-income-history-user_data
8687
+ :see: https://binance-docs.github.io/apidocs/pm/en/#get-cm-income-history-user_data
8457
8688
  :param str symbol: unified market symbol
8458
8689
  :param int [since]: the earliest time in ms to fetch funding history for
8459
8690
  :param int [limit]: the maximum number of funding history structures to retrieve
8460
8691
  :param dict [params]: extra parameters specific to the exchange API endpoint
8692
+ :param int [params.until]: timestamp in ms of the latest funding history entry
8693
+ :param boolean [params.portfolioMargin]: set to True if you would like to fetch the funding history for a portfolio margin account
8461
8694
  :returns dict: a `funding history structure <https://docs.ccxt.com/#/?id=funding-history-structure>`
8462
8695
  """
8463
8696
  await self.load_markets()
@@ -8472,6 +8705,9 @@ class binance(Exchange, ImplicitAPI):
8472
8705
  raise NotSupported(self.id + ' fetchFundingHistory() supports swap contracts only')
8473
8706
  subType = None
8474
8707
  subType, params = self.handle_sub_type_and_params('fetchFundingHistory', market, params, 'linear')
8708
+ isPortfolioMargin = None
8709
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'fetchFundingHistory', 'papi', 'portfolioMargin', False)
8710
+ request, params = self.handle_until_option('endTime', request, params)
8475
8711
  if since is not None:
8476
8712
  request['startTime'] = since
8477
8713
  if limit is not None:
@@ -8481,9 +8717,15 @@ class binance(Exchange, ImplicitAPI):
8481
8717
  params = self.omit(params, 'type')
8482
8718
  response = None
8483
8719
  if self.is_linear(type, subType):
8484
- response = await self.fapiPrivateGetIncome(self.extend(request, params))
8720
+ if isPortfolioMargin:
8721
+ response = await self.papiGetUmIncome(self.extend(request, params))
8722
+ else:
8723
+ response = await self.fapiPrivateGetIncome(self.extend(request, params))
8485
8724
  elif self.is_inverse(type, subType):
8486
- response = await self.dapiPrivateGetIncome(self.extend(request, params))
8725
+ if isPortfolioMargin:
8726
+ response = await self.papiGetCmIncome(self.extend(request, params))
8727
+ else:
8728
+ response = await self.dapiPrivateGetIncome(self.extend(request, params))
8487
8729
  else:
8488
8730
  raise NotSupported(self.id + ' fetchFundingHistory() supports linear and inverse contracts only')
8489
8731
  return self.parse_incomes(response, market, since, limit)
@@ -8493,9 +8735,12 @@ class binance(Exchange, ImplicitAPI):
8493
8735
  set the level of leverage for a market
8494
8736
  :see: https://binance-docs.github.io/apidocs/futures/en/#change-initial-leverage-trade
8495
8737
  :see: https://binance-docs.github.io/apidocs/delivery/en/#change-initial-leverage-trade
8738
+ :see: https://binance-docs.github.io/apidocs/pm/en/#change-um-initial-leverage-trade
8739
+ :see: https://binance-docs.github.io/apidocs/pm/en/#change-cm-initial-leverage-trade
8496
8740
  :param float leverage: the rate of leverage
8497
8741
  :param str symbol: unified market symbol
8498
8742
  :param dict [params]: extra parameters specific to the exchange API endpoint
8743
+ :param boolean [params.portfolioMargin]: set to True if you would like to set the leverage for a trading pair in a portfolio margin account
8499
8744
  :returns dict: response from the exchange
8500
8745
  """
8501
8746
  if symbol is None:
@@ -8510,11 +8755,19 @@ class binance(Exchange, ImplicitAPI):
8510
8755
  'symbol': market['id'],
8511
8756
  'leverage': leverage,
8512
8757
  }
8758
+ isPortfolioMargin = None
8759
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'setLeverage', 'papi', 'portfolioMargin', False)
8513
8760
  response = None
8514
8761
  if market['linear']:
8515
- response = await self.fapiPrivatePostLeverage(self.extend(request, params))
8762
+ if isPortfolioMargin:
8763
+ response = await self.papiPostUmLeverage(self.extend(request, params))
8764
+ else:
8765
+ response = await self.fapiPrivatePostLeverage(self.extend(request, params))
8516
8766
  elif market['inverse']:
8517
- response = await self.dapiPrivatePostLeverage(self.extend(request, params))
8767
+ if isPortfolioMargin:
8768
+ response = await self.papiPostCmLeverage(self.extend(request, params))
8769
+ else:
8770
+ response = await self.dapiPrivatePostLeverage(self.extend(request, params))
8518
8771
  else:
8519
8772
  raise NotSupported(self.id + ' setLeverage() supports linear and inverse contracts only')
8520
8773
  return response
@@ -8573,14 +8826,17 @@ class binance(Exchange, ImplicitAPI):
8573
8826
  raise e
8574
8827
  return response
8575
8828
 
8576
- async def set_position_mode(self, hedged, symbol: Str = None, params={}):
8829
+ async def set_position_mode(self, hedged: bool, symbol: Str = None, params={}):
8577
8830
  """
8578
8831
  set hedged to True or False for a market
8579
8832
  :see: https://binance-docs.github.io/apidocs/futures/en/#change-position-mode-trade
8580
8833
  :see: https://binance-docs.github.io/apidocs/delivery/en/#change-position-mode-trade
8834
+ :see: https://binance-docs.github.io/apidocs/pm/en/#change-um-position-mode-trade
8835
+ :see: https://binance-docs.github.io/apidocs/pm/en/#change-cm-position-mode-trade
8581
8836
  :param bool hedged: set to True to use dualSidePosition
8582
8837
  :param str symbol: not used by binance setPositionMode()
8583
8838
  :param dict [params]: extra parameters specific to the exchange API endpoint
8839
+ :param boolean [params.portfolioMargin]: set to True if you would like to set the position mode for a portfolio margin account
8584
8840
  :returns dict: response from the exchange
8585
8841
  """
8586
8842
  defaultType = self.safe_string(self.options, 'defaultType', 'future')
@@ -8588,6 +8844,8 @@ class binance(Exchange, ImplicitAPI):
8588
8844
  params = self.omit(params, ['type'])
8589
8845
  subType = None
8590
8846
  subType, params = self.handle_sub_type_and_params('setPositionMode', None, params)
8847
+ isPortfolioMargin = None
8848
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'setPositionMode', 'papi', 'portfolioMargin', False)
8591
8849
  dualSidePosition = None
8592
8850
  if hedged:
8593
8851
  dualSidePosition = 'true'
@@ -8598,10 +8856,15 @@ class binance(Exchange, ImplicitAPI):
8598
8856
  }
8599
8857
  response = None
8600
8858
  if self.is_inverse(type, subType):
8601
- response = await self.dapiPrivatePostPositionSideDual(self.extend(request, params))
8859
+ if isPortfolioMargin:
8860
+ response = await self.papiPostCmPositionSideDual(self.extend(request, params))
8861
+ else:
8862
+ response = await self.dapiPrivatePostPositionSideDual(self.extend(request, params))
8602
8863
  else:
8603
- # default to future
8604
- response = await self.fapiPrivatePostPositionSideDual(self.extend(request, params))
8864
+ if isPortfolioMargin:
8865
+ response = await self.papiPostUmPositionSideDual(self.extend(request, params))
8866
+ else:
8867
+ response = await self.fapiPrivatePostPositionSideDual(self.extend(request, params))
8605
8868
  #
8606
8869
  # {
8607
8870
  # "code": 200,
@@ -8785,12 +9048,15 @@ class binance(Exchange, ImplicitAPI):
8785
9048
  :see: https://binance-docs.github.io/apidocs/voptions/en/#account-funding-flow-user_data
8786
9049
  :see: https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data
8787
9050
  :see: https://binance-docs.github.io/apidocs/delivery/en/#get-income-history-user_data
9051
+ :see: https://binance-docs.github.io/apidocs/pm/en/#get-um-income-history-user_data
9052
+ :see: https://binance-docs.github.io/apidocs/pm/en/#get-cm-income-history-user_data
8788
9053
  :param str code: unified currency code
8789
9054
  :param int [since]: timestamp in ms of the earliest ledger entry
8790
9055
  :param int [limit]: max number of ledger entrys to return
8791
9056
  :param dict [params]: extra parameters specific to the exchange API endpoint
8792
9057
  :param int [params.until]: timestamp in ms of the latest ledger entry
8793
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
9058
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
9059
+ :param boolean [params.portfolioMargin]: set to True if you would like to fetch the ledger for a portfolio margin account
8794
9060
  :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
8795
9061
  """
8796
9062
  await self.load_markets()
@@ -8814,15 +9080,23 @@ class binance(Exchange, ImplicitAPI):
8814
9080
  if until is not None:
8815
9081
  params = self.omit(params, 'until')
8816
9082
  request['endTime'] = until
9083
+ isPortfolioMargin = None
9084
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'fetchLedger', 'papi', 'portfolioMargin', False)
8817
9085
  response = None
8818
9086
  if type == 'option':
8819
9087
  self.check_required_argument('fetchLedger', code, 'code')
8820
9088
  request['currency'] = currency['id']
8821
9089
  response = await self.eapiPrivateGetBill(self.extend(request, params))
8822
9090
  elif self.is_linear(type, subType):
8823
- response = await self.fapiPrivateGetIncome(self.extend(request, params))
9091
+ if isPortfolioMargin:
9092
+ response = await self.papiGetUmIncome(self.extend(request, params))
9093
+ else:
9094
+ response = await self.fapiPrivateGetIncome(self.extend(request, params))
8824
9095
  elif self.is_inverse(type, subType):
8825
- response = await self.dapiPrivateGetIncome(self.extend(request, params))
9096
+ if isPortfolioMargin:
9097
+ response = await self.papiGetCmIncome(self.extend(request, params))
9098
+ else:
9099
+ response = await self.dapiPrivateGetIncome(self.extend(request, params))
8826
9100
  else:
8827
9101
  raise NotSupported(self.id + ' fetchLedger() supports contract wallets only')
8828
9102
  #
@@ -8838,7 +9112,7 @@ class binance(Exchange, ImplicitAPI):
8838
9112
  # }
8839
9113
  # ]
8840
9114
  #
8841
- # futures(fapi, dapi)
9115
+ # futures(fapi, dapi, papi)
8842
9116
  #
8843
9117
  # [
8844
9118
  # {
@@ -8867,7 +9141,7 @@ class binance(Exchange, ImplicitAPI):
8867
9141
  # "createDate": 1676621042489
8868
9142
  # }
8869
9143
  #
8870
- # futures(fapi, dapi)
9144
+ # futures(fapi, dapi, papi)
8871
9145
  #
8872
9146
  # {
8873
9147
  # "symbol": "",
@@ -8966,7 +9240,7 @@ class binance(Exchange, ImplicitAPI):
8966
9240
  isSpotOrMargin = (api.find('sapi') > -1 or api == 'private')
8967
9241
  marketType = 'spot' if isSpotOrMargin else 'future'
8968
9242
  defaultId = 'x-xcKtGhcu' if (not isSpotOrMargin) else 'x-R4BD3S82'
8969
- broker = self.safe_value(self.options, 'broker', {})
9243
+ broker = self.safe_dict(self.options, 'broker', {})
8970
9244
  brokerId = self.safe_string(broker, marketType, defaultId)
8971
9245
  params['newClientOrderId'] = brokerId + self.uuid22()
8972
9246
  query = None
@@ -8988,8 +9262,8 @@ class binance(Exchange, ImplicitAPI):
8988
9262
  query = self.urlencode_with_array_repeat(extendedParams)
8989
9263
  elif (path == 'batchOrders') or (path.find('sub-account') >= 0) or (path == 'capital/withdraw/apply') or (path.find('staking') >= 0):
8990
9264
  if (method == 'DELETE') and (path == 'batchOrders'):
8991
- orderidlist = self.safe_value(extendedParams, 'orderidlist', [])
8992
- origclientorderidlist = self.safe_value(extendedParams, 'origclientorderidlist', [])
9265
+ orderidlist = self.safe_list(extendedParams, 'orderidlist', [])
9266
+ origclientorderidlist = self.safe_list(extendedParams, 'origclientorderidlist', [])
8993
9267
  extendedParams = self.omit(extendedParams, ['orderidlist', 'origclientorderidlist'])
8994
9268
  query = self.rawencode(extendedParams)
8995
9269
  orderidlistLength = len(orderidlist)
@@ -9038,8 +9312,8 @@ class binance(Exchange, ImplicitAPI):
9038
9312
  elif url.startswith('https://papi.' + hostname + '/'):
9039
9313
  marketType = 'portfoliomargin'
9040
9314
  if marketType is not None:
9041
- exceptionsForMarketType = self.safe_value(self.exceptions, marketType, {})
9042
- return self.safe_value(exceptionsForMarketType, exactOrBroad, {})
9315
+ exceptionsForMarketType = self.safe_dict(self.exceptions, marketType, {})
9316
+ return self.safe_dict(exceptionsForMarketType, exactOrBroad, {})
9043
9317
  return {}
9044
9318
 
9045
9319
  def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
@@ -9235,7 +9509,7 @@ class binance(Exchange, ImplicitAPI):
9235
9509
  # },
9236
9510
  # ]
9237
9511
  #
9238
- rate = self.safe_value(response, 0)
9512
+ rate = self.safe_dict(response, 0)
9239
9513
  return self.parse_borrow_rate(rate)
9240
9514
 
9241
9515
  async def fetch_borrow_rate_history(self, code: str, since: Int = None, limit: Int = None, params={}):
@@ -9331,7 +9605,7 @@ class binance(Exchange, ImplicitAPI):
9331
9605
  # "success": True
9332
9606
  # }
9333
9607
  #
9334
- data = self.safe_value(response, 'data')
9608
+ data = self.safe_dict(response, 'data')
9335
9609
  giftcardCode = self.safe_string(data, 'code')
9336
9610
  id = self.safe_string(data, 'referenceNo')
9337
9611
  return {
@@ -9430,7 +9704,7 @@ class binance(Exchange, ImplicitAPI):
9430
9704
  # "total": 1
9431
9705
  # }
9432
9706
  #
9433
- rows = self.safe_value(response, 'rows')
9707
+ rows = self.safe_list(response, 'rows')
9434
9708
  interest = self.parse_borrow_interests(rows, market)
9435
9709
  return self.filter_by_currency_since_limit(interest, code, since, limit)
9436
9710
 
@@ -9455,9 +9729,11 @@ class binance(Exchange, ImplicitAPI):
9455
9729
  """
9456
9730
  repay borrowed margin and interest
9457
9731
  :see: https://binance-docs.github.io/apidocs/spot/en/#margin-account-borrow-repay-margin
9732
+ :see: https://binance-docs.github.io/apidocs/pm/en/#margin-account-repay-margin
9458
9733
  :param str code: unified currency code of the currency to repay
9459
9734
  :param float amount: the amount to repay
9460
9735
  :param dict [params]: extra parameters specific to the exchange API endpoint
9736
+ :param boolean [params.portfolioMargin]: set to True if you would like to repay margin in a portfolio margin account
9461
9737
  :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
9462
9738
  """
9463
9739
  await self.load_markets()
@@ -9465,10 +9741,16 @@ class binance(Exchange, ImplicitAPI):
9465
9741
  request = {
9466
9742
  'asset': currency['id'],
9467
9743
  'amount': self.currency_to_precision(code, amount),
9468
- 'isIsolated': 'FALSE',
9469
- 'type': 'REPAY',
9470
9744
  }
9471
- response = await self.sapiPostMarginBorrowRepay(self.extend(request, params))
9745
+ response = None
9746
+ isPortfolioMargin = None
9747
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'repayCrossMargin', 'papi', 'portfolioMargin', False)
9748
+ if isPortfolioMargin:
9749
+ response = await self.papiPostRepayLoan(self.extend(request, params))
9750
+ else:
9751
+ request['isIsolated'] = 'FALSE'
9752
+ request['type'] = 'REPAY'
9753
+ response = await self.sapiPostMarginBorrowRepay(self.extend(request, params))
9472
9754
  #
9473
9755
  # {
9474
9756
  # "tranId": 108988250265,
@@ -9510,9 +9792,11 @@ class binance(Exchange, ImplicitAPI):
9510
9792
  """
9511
9793
  create a loan to borrow margin
9512
9794
  :see: https://binance-docs.github.io/apidocs/spot/en/#margin-account-borrow-repay-margin
9795
+ :see: https://binance-docs.github.io/apidocs/pm/en/#margin-account-borrow-margin
9513
9796
  :param str code: unified currency code of the currency to borrow
9514
9797
  :param float amount: the amount to borrow
9515
9798
  :param dict [params]: extra parameters specific to the exchange API endpoint
9799
+ :param boolean [params.portfolioMargin]: set to True if you would like to borrow margin in a portfolio margin account
9516
9800
  :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
9517
9801
  """
9518
9802
  await self.load_markets()
@@ -9520,10 +9804,16 @@ class binance(Exchange, ImplicitAPI):
9520
9804
  request = {
9521
9805
  'asset': currency['id'],
9522
9806
  'amount': self.currency_to_precision(code, amount),
9523
- 'isIsolated': 'FALSE',
9524
- 'type': 'BORROW',
9525
9807
  }
9526
- response = await self.sapiPostMarginBorrowRepay(self.extend(request, params))
9808
+ response = None
9809
+ isPortfolioMargin = None
9810
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'borrowCrossMargin', 'papi', 'portfolioMargin', False)
9811
+ if isPortfolioMargin:
9812
+ response = await self.papiPostMarginLoan(self.extend(request, params))
9813
+ else:
9814
+ request['isIsolated'] = 'FALSE'
9815
+ request['type'] = 'BORROW'
9816
+ response = await self.sapiPostMarginBorrowRepay(self.extend(request, params))
9527
9817
  #
9528
9818
  # {
9529
9819
  # "tranId": 108988250265,