ccxt 4.2.39__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.

@@ -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
 
@@ -5029,7 +5029,7 @@ class binance(Exchange, ImplicitAPI):
5029
5029
  cost = self.safe_string(order, 'cumBase', cost)
5030
5030
  type = self.safe_string_lower(order, 'type')
5031
5031
  side = self.safe_string_lower(order, 'side')
5032
- fills = self.safe_value(order, 'fills', [])
5032
+ fills = self.safe_list(order, 'fills', [])
5033
5033
  timeInForce = self.safe_string(order, 'timeInForce')
5034
5034
  if timeInForce == 'GTX':
5035
5035
  # GTX means "Good Till Crossing" and is an equivalent way of saying Post Only
@@ -5059,7 +5059,7 @@ class binance(Exchange, ImplicitAPI):
5059
5059
  'type': type,
5060
5060
  'timeInForce': timeInForce,
5061
5061
  'postOnly': postOnly,
5062
- 'reduceOnly': self.safe_value(order, 'reduceOnly'),
5062
+ 'reduceOnly': self.safe_bool(order, 'reduceOnly'),
5063
5063
  'side': side,
5064
5064
  'price': price,
5065
5065
  'triggerPrice': stopPrice,
@@ -5091,7 +5091,7 @@ class binance(Exchange, ImplicitAPI):
5091
5091
  side = self.safe_string(rawOrder, 'side')
5092
5092
  amount = self.safe_value(rawOrder, 'amount')
5093
5093
  price = self.safe_value(rawOrder, 'price')
5094
- orderParams = self.safe_value(rawOrder, 'params', {})
5094
+ orderParams = self.safe_dict(rawOrder, 'params', {})
5095
5095
  orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
5096
5096
  ordersRequests.append(orderRequest)
5097
5097
  orderSymbols = self.market_symbols(orderSymbols, None, False, True, True)
@@ -6242,11 +6242,11 @@ class binance(Exchange, ImplicitAPI):
6242
6242
  # },
6243
6243
  # ]
6244
6244
  # }
6245
- results = self.safe_value(response, 'userAssetDribblets', [])
6245
+ results = self.safe_list(response, 'userAssetDribblets', [])
6246
6246
  rows = self.safe_integer(response, 'total', 0)
6247
6247
  data = []
6248
6248
  for i in range(0, rows):
6249
- logs = self.safe_value(results[i], 'userAssetDribbletDetails', [])
6249
+ logs = self.safe_list(results[i], 'userAssetDribbletDetails', [])
6250
6250
  for j in range(0, len(logs)):
6251
6251
  logs[j]['isDustTrade'] = True
6252
6252
  data.append(logs[j])
@@ -6343,7 +6343,7 @@ class binance(Exchange, ImplicitAPI):
6343
6343
  currency = None
6344
6344
  response = None
6345
6345
  request = {}
6346
- legalMoney = self.safe_value(self.options, 'legalMoney', {})
6346
+ legalMoney = self.safe_dict(self.options, 'legalMoney', {})
6347
6347
  fiatOnly = self.safe_bool(params, 'fiat', False)
6348
6348
  params = self.omit(params, 'fiatOnly')
6349
6349
  until = self.safe_integer(params, 'until')
@@ -6442,7 +6442,7 @@ class binance(Exchange, ImplicitAPI):
6442
6442
  paginate, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'paginate')
6443
6443
  if paginate:
6444
6444
  return await self.fetch_paginated_call_dynamic('fetchWithdrawals', code, since, limit, params)
6445
- legalMoney = self.safe_value(self.options, 'legalMoney', {})
6445
+ legalMoney = self.safe_dict(self.options, 'legalMoney', {})
6446
6446
  fiatOnly = self.safe_bool(params, 'fiat', False)
6447
6447
  params = self.omit(params, 'fiatOnly')
6448
6448
  request = {}
@@ -6577,7 +6577,7 @@ class binance(Exchange, ImplicitAPI):
6577
6577
  'Refund Failed': 'failed',
6578
6578
  },
6579
6579
  }
6580
- statuses = self.safe_value(statusesByType, type, {})
6580
+ statuses = self.safe_dict(statusesByType, type, {})
6581
6581
  return self.safe_string(statuses, status, status)
6582
6582
 
6583
6583
  def parse_transaction(self, transaction, currency: Currency = None) -> Transaction:
@@ -6734,7 +6734,7 @@ class binance(Exchange, ImplicitAPI):
6734
6734
  type = self.safe_string(transfer, 'type')
6735
6735
  fromAccount = None
6736
6736
  toAccount = None
6737
- accountsById = self.safe_value(self.options, 'accountsById', {})
6737
+ accountsById = self.safe_dict(self.options, 'accountsById', {})
6738
6738
  if type is not None:
6739
6739
  parts = type.split('_')
6740
6740
  fromAccount = self.safe_value(parts, 0)
@@ -6769,20 +6769,16 @@ class binance(Exchange, ImplicitAPI):
6769
6769
  # }
6770
6770
  #
6771
6771
  marketId = self.safe_string(income, 'symbol')
6772
- symbol = self.safe_symbol(marketId, market, None, 'swap')
6773
- amount = self.safe_number(income, 'income')
6774
6772
  currencyId = self.safe_string(income, 'asset')
6775
- code = self.safe_currency_code(currencyId)
6776
- id = self.safe_string(income, 'tranId')
6777
6773
  timestamp = self.safe_integer(income, 'time')
6778
6774
  return {
6779
6775
  'info': income,
6780
- 'symbol': symbol,
6781
- 'code': code,
6776
+ 'symbol': self.safe_symbol(marketId, market, None, 'swap'),
6777
+ 'code': self.safe_currency_code(currencyId),
6782
6778
  'timestamp': timestamp,
6783
6779
  'datetime': self.iso8601(timestamp),
6784
- 'id': id,
6785
- 'amount': amount,
6780
+ 'id': self.safe_string(income, 'tranId'),
6781
+ 'amount': self.safe_number(income, 'income'),
6786
6782
  }
6787
6783
 
6788
6784
  async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
@@ -6823,7 +6819,7 @@ class binance(Exchange, ImplicitAPI):
6823
6819
  if toId == 'ISOLATED':
6824
6820
  if symbol is None:
6825
6821
  raise ArgumentsRequired(self.id + ' transfer() requires params["symbol"] when toAccount is ' + toAccount)
6826
- accountsById = self.safe_value(self.options, 'accountsById', {})
6822
+ accountsById = self.safe_dict(self.options, 'accountsById', {})
6827
6823
  fromIsolated = not (fromId in accountsById)
6828
6824
  toIsolated = not (toId in accountsById)
6829
6825
  if fromIsolated and (market is None):
@@ -6896,7 +6892,7 @@ class binance(Exchange, ImplicitAPI):
6896
6892
  defaultTo = 'spot' if (fromAccount == 'future') else 'future'
6897
6893
  toAccount = self.safe_string(params, 'toAccount', defaultTo)
6898
6894
  type = self.safe_string(params, 'type')
6899
- accountsByType = self.safe_value(self.options, 'accountsByType', {})
6895
+ accountsByType = self.safe_dict(self.options, 'accountsByType', {})
6900
6896
  fromId = self.safe_string(accountsByType, fromAccount)
6901
6897
  toId = self.safe_string(accountsByType, toAccount)
6902
6898
  if type is None:
@@ -6934,7 +6930,7 @@ class binance(Exchange, ImplicitAPI):
6934
6930
  # ]
6935
6931
  # }
6936
6932
  #
6937
- rows = self.safe_value(response, 'rows', [])
6933
+ rows = self.safe_list(response, 'rows', [])
6938
6934
  return self.parse_transfers(rows, currency, since, limit)
6939
6935
 
6940
6936
  async def fetch_deposit_address(self, code: str, params={}):
@@ -6951,7 +6947,7 @@ class binance(Exchange, ImplicitAPI):
6951
6947
  'coin': currency['id'],
6952
6948
  # 'network': 'ETH', # 'BSC', 'XMR', you can get network and isDefault in networkList in the response of sapiGetCapitalConfigDetail
6953
6949
  }
6954
- networks = self.safe_value(self.options, 'networks', {})
6950
+ networks = self.safe_dict(self.options, 'networks', {})
6955
6951
  network = self.safe_string_upper(params, 'network') # self line allows the user to specify either ERC20 or ETH
6956
6952
  network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
6957
6953
  if network is not None:
@@ -6977,7 +6973,7 @@ class binance(Exchange, ImplicitAPI):
6977
6973
  url = self.safe_string(response, 'url')
6978
6974
  impliedNetwork = None
6979
6975
  if url is not None:
6980
- reverseNetworks = self.safe_value(self.options, 'reverseNetworks', {})
6976
+ reverseNetworks = self.safe_dict(self.options, 'reverseNetworks', {})
6981
6977
  parts = url.split('/')
6982
6978
  topLevel = self.safe_string(parts, 2)
6983
6979
  if (topLevel == 'blockchair.com') or (topLevel == 'viewblock.io'):
@@ -6990,7 +6986,7 @@ class binance(Exchange, ImplicitAPI):
6990
6986
  'TRX': {'TRC20': 'TRX'},
6991
6987
  })
6992
6988
  if code in impliedNetworks:
6993
- conversion = self.safe_value(impliedNetworks, code, {})
6989
+ conversion = self.safe_dict(impliedNetworks, code, {})
6994
6990
  impliedNetwork = self.safe_string(conversion, impliedNetwork, impliedNetwork)
6995
6991
  tag = self.safe_string(response, 'tag', '')
6996
6992
  if len(tag) == 0:
@@ -7101,7 +7097,7 @@ class binance(Exchange, ImplicitAPI):
7101
7097
  entry = response[i]
7102
7098
  currencyId = self.safe_string(entry, 'coin')
7103
7099
  code = self.safe_currency_code(currencyId)
7104
- networkList = self.safe_value(entry, 'networkList', [])
7100
+ networkList = self.safe_list(entry, 'networkList', [])
7105
7101
  withdrawFees[code] = {}
7106
7102
  for j in range(0, len(networkList)):
7107
7103
  networkEntry = networkList[j]
@@ -7210,14 +7206,14 @@ class binance(Exchange, ImplicitAPI):
7210
7206
  # ]
7211
7207
  # }
7212
7208
  #
7213
- networkList = self.safe_value(fee, 'networkList', [])
7209
+ networkList = self.safe_list(fee, 'networkList', [])
7214
7210
  result = self.deposit_withdraw_fee(fee)
7215
7211
  for j in range(0, len(networkList)):
7216
7212
  networkEntry = networkList[j]
7217
7213
  networkId = self.safe_string(networkEntry, 'network')
7218
7214
  networkCode = self.network_id_to_code(networkId)
7219
7215
  withdrawFee = self.safe_number(networkEntry, 'withdrawFee')
7220
- isDefault = self.safe_value(networkEntry, 'isDefault')
7216
+ isDefault = self.safe_bool(networkEntry, 'isDefault')
7221
7217
  if isDefault is True:
7222
7218
  result['withdraw'] = {
7223
7219
  'fee': withdrawFee,
@@ -7260,7 +7256,7 @@ class binance(Exchange, ImplicitAPI):
7260
7256
  }
7261
7257
  if tag is not None:
7262
7258
  request['addressTag'] = tag
7263
- networks = self.safe_value(self.options, 'networks', {})
7259
+ networks = self.safe_dict(self.options, 'networks', {})
7264
7260
  network = self.safe_string_upper(params, 'network') # self line allows the user to specify either ERC20 or ETH
7265
7261
  network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
7266
7262
  if network is not None:
@@ -7346,7 +7342,7 @@ class binance(Exchange, ImplicitAPI):
7346
7342
  #
7347
7343
  data = response
7348
7344
  if isinstance(data, list):
7349
- data = self.safe_value(data, 0, {})
7345
+ data = self.safe_dict(data, 0, {})
7350
7346
  return self.parse_trading_fee(data)
7351
7347
 
7352
7348
  async def fetch_trading_fees(self, params={}):
@@ -7720,8 +7716,8 @@ class binance(Exchange, ImplicitAPI):
7720
7716
  }
7721
7717
 
7722
7718
  def parse_account_positions(self, account):
7723
- positions = self.safe_value(account, 'positions')
7724
- assets = self.safe_value(account, 'assets', [])
7719
+ positions = self.safe_list(account, 'positions')
7720
+ assets = self.safe_list(account, 'assets', [])
7725
7721
  balances = {}
7726
7722
  for i in range(0, len(assets)):
7727
7723
  entry = assets[i]
@@ -7739,18 +7735,22 @@ class binance(Exchange, ImplicitAPI):
7739
7735
  marketId = self.safe_string(position, 'symbol')
7740
7736
  market = self.safe_market(marketId, None, None, 'contract')
7741
7737
  code = market['quote'] if market['linear'] else market['base']
7742
- # sometimes not all the codes are correctly returned...
7743
- if code in balances:
7744
- parsed = self.parse_account_position(self.extend(position, {
7745
- 'crossMargin': balances[code]['crossMargin'],
7746
- 'crossWalletBalance': balances[code]['crossWalletBalance'],
7747
- }), market)
7748
- 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)
7749
7748
  return result
7750
7749
 
7751
7750
  def parse_account_position(self, position, market: Market = None):
7752
7751
  #
7753
7752
  # usdm
7753
+ #
7754
7754
  # {
7755
7755
  # "symbol": "BTCBUSD",
7756
7756
  # "initialMargin": "0",
@@ -7771,6 +7771,7 @@ class binance(Exchange, ImplicitAPI):
7771
7771
  # }
7772
7772
  #
7773
7773
  # coinm
7774
+ #
7774
7775
  # {
7775
7776
  # "symbol": "BTCUSD_210625",
7776
7777
  # "initialMargin": "0.00024393",
@@ -7789,6 +7790,46 @@ class binance(Exchange, ImplicitAPI):
7789
7790
  # "crossWalletBalance": "34",
7790
7791
  # }
7791
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
+ #
7792
7833
  marketId = self.safe_string(position, 'symbol')
7793
7834
  market = self.safe_market(marketId, market, None, 'contract')
7794
7835
  symbol = self.safe_string(market, 'symbol')
@@ -7817,8 +7858,8 @@ class binance(Exchange, ImplicitAPI):
7817
7858
  contractsString = Precise.string_div(entryNotional, contractSizeNew)
7818
7859
  contractsStringAbs = Precise.string_div(Precise.string_add(contractsString, '0.5'), '1', 0)
7819
7860
  contracts = self.parse_number(contractsStringAbs)
7820
- leverageBrackets = self.safe_value(self.options, 'leverageBrackets', {})
7821
- leverageBracket = self.safe_value(leverageBrackets, symbol, [])
7861
+ leverageBrackets = self.safe_dict(self.options, 'leverageBrackets', {})
7862
+ leverageBracket = self.safe_list(leverageBrackets, symbol, [])
7822
7863
  maintenanceMarginPercentageString = None
7823
7864
  for i in range(0, len(leverageBracket)):
7824
7865
  bracket = leverageBracket[i]
@@ -7831,7 +7872,7 @@ class binance(Exchange, ImplicitAPI):
7831
7872
  timestamp = self.safe_integer(position, 'updateTime')
7832
7873
  if timestamp == 0:
7833
7874
  timestamp = None
7834
- isolated = self.safe_value(position, 'isolated')
7875
+ isolated = self.safe_bool(position, 'isolated')
7835
7876
  marginMode = None
7836
7877
  collateralString = None
7837
7878
  walletBalance = None
@@ -7973,11 +8014,45 @@ class binance(Exchange, ImplicitAPI):
7973
8014
  # "isolatedWallet": "0.00268058"
7974
8015
  # }
7975
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
+ #
7976
8051
  marketId = self.safe_string(position, 'symbol')
7977
8052
  market = self.safe_market(marketId, market, None, 'contract')
7978
8053
  symbol = self.safe_string(market, 'symbol')
7979
- leverageBrackets = self.safe_value(self.options, 'leverageBrackets', {})
7980
- leverageBracket = self.safe_value(leverageBrackets, symbol, [])
8054
+ leverageBrackets = self.safe_dict(self.options, 'leverageBrackets', {})
8055
+ leverageBracket = self.safe_list(leverageBrackets, symbol, [])
7981
8056
  notionalString = self.safe_string_2(position, 'notional', 'notionalValue')
7982
8057
  notionalStringAbs = Precise.string_abs(notionalString)
7983
8058
  maintenanceMarginPercentageString = None
@@ -8010,7 +8085,7 @@ class binance(Exchange, ImplicitAPI):
8010
8085
  linear = ('notional' in position)
8011
8086
  if marginMode == 'cross':
8012
8087
  # calculate collateral
8013
- precision = self.safe_value(market, 'precision', {})
8088
+ precision = self.safe_dict(market, 'precision', {})
8014
8089
  if linear:
8015
8090
  # walletBalance = (liquidationPrice * (±1 + mmp) ± entryPrice) * contracts
8016
8091
  onePlusMaintenanceMarginPercentageString = None
@@ -8104,11 +8179,19 @@ class binance(Exchange, ImplicitAPI):
8104
8179
  query = self.omit(params, 'type')
8105
8180
  subType = None
8106
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)
8107
8184
  response = None
8108
8185
  if self.is_linear(type, subType):
8109
- response = await self.fapiPrivateGetLeverageBracket(query)
8186
+ if isPortfolioMargin:
8187
+ response = await self.papiGetUmLeverageBracket(query)
8188
+ else:
8189
+ response = await self.fapiPrivateGetLeverageBracket(query)
8110
8190
  elif self.is_inverse(type, subType):
8111
- response = await self.dapiPrivateV2GetLeverageBracket(query)
8191
+ if isPortfolioMargin:
8192
+ response = await self.papiGetCmLeverageBracket(query)
8193
+ else:
8194
+ response = await self.dapiPrivateV2GetLeverageBracket(query)
8112
8195
  else:
8113
8196
  raise NotSupported(self.id + ' loadLeverageBrackets() supports linear and inverse contracts only')
8114
8197
  self.options['leverageBrackets'] = {}
@@ -8116,7 +8199,7 @@ class binance(Exchange, ImplicitAPI):
8116
8199
  entry = response[i]
8117
8200
  marketId = self.safe_string(entry, 'symbol')
8118
8201
  symbol = self.safe_symbol(marketId, None, None, 'contract')
8119
- brackets = self.safe_value(entry, 'brackets', [])
8202
+ brackets = self.safe_list(entry, 'brackets', [])
8120
8203
  result = []
8121
8204
  for j in range(0, len(brackets)):
8122
8205
  bracket = brackets[j]
@@ -8131,8 +8214,11 @@ class binance(Exchange, ImplicitAPI):
8131
8214
  retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
8132
8215
  :see: https://binance-docs.github.io/apidocs/futures/en/#notional-and-leverage-brackets-user_data
8133
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
8134
8219
  :param str[]|None symbols: list of unified market symbols
8135
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
8136
8222
  :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
8137
8223
  """
8138
8224
  await self.load_markets()
@@ -8140,11 +8226,19 @@ class binance(Exchange, ImplicitAPI):
8140
8226
  type, params = self.handle_market_type_and_params('fetchLeverageTiers', None, params)
8141
8227
  subType = None
8142
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)
8143
8231
  response = None
8144
8232
  if self.is_linear(type, subType):
8145
- response = await self.fapiPrivateGetLeverageBracket(params)
8233
+ if isPortfolioMargin:
8234
+ response = await self.papiGetUmLeverageBracket(params)
8235
+ else:
8236
+ response = await self.fapiPrivateGetLeverageBracket(params)
8146
8237
  elif self.is_inverse(type, subType):
8147
- response = await self.dapiPrivateV2GetLeverageBracket(params)
8238
+ if isPortfolioMargin:
8239
+ response = await self.papiGetCmLeverageBracket(params)
8240
+ else:
8241
+ response = await self.dapiPrivateV2GetLeverageBracket(params)
8148
8242
  else:
8149
8243
  raise NotSupported(self.id + ' fetchLeverageTiers() supports linear and inverse contracts only')
8150
8244
  #
@@ -8211,7 +8305,7 @@ class binance(Exchange, ImplicitAPI):
8211
8305
  #
8212
8306
  marketId = self.safe_string(info, 'symbol')
8213
8307
  market = self.safe_market(marketId, market, None, 'contract')
8214
- brackets = self.safe_value(info, 'brackets', [])
8308
+ brackets = self.safe_list(info, 'brackets', [])
8215
8309
  tiers = []
8216
8310
  for j in range(0, len(brackets)):
8217
8311
  bracket = brackets[j]
@@ -8406,8 +8500,11 @@ class binance(Exchange, ImplicitAPI):
8406
8500
  fetch account positions
8407
8501
  :see: https://binance-docs.github.io/apidocs/futures/en/#account-information-v2-user_data
8408
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
8409
8505
  :param str[]|None symbols: list of unified market symbols
8410
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
8411
8508
  :returns dict: data on account positions
8412
8509
  """
8413
8510
  if symbols is not None:
@@ -8417,14 +8514,22 @@ class binance(Exchange, ImplicitAPI):
8417
8514
  await self.load_leverage_brackets(False, params)
8418
8515
  defaultType = self.safe_string(self.options, 'defaultType', 'future')
8419
8516
  type = self.safe_string(params, 'type', defaultType)
8420
- query = self.omit(params, 'type')
8517
+ params = self.omit(params, 'type')
8421
8518
  subType = None
8422
- 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)
8423
8522
  response = None
8424
8523
  if self.is_linear(type, subType):
8425
- response = await self.fapiPrivateV2GetAccount(query)
8524
+ if isPortfolioMargin:
8525
+ response = await self.papiGetUmAccount(params)
8526
+ else:
8527
+ response = await self.fapiPrivateV2GetAccount(params)
8426
8528
  elif self.is_inverse(type, subType):
8427
- response = await self.dapiPrivateGetAccount(query)
8529
+ if isPortfolioMargin:
8530
+ response = await self.papiGetCmAccount(params)
8531
+ else:
8532
+ response = await self.dapiPrivateGetAccount(params)
8428
8533
  else:
8429
8534
  raise NotSupported(self.id + ' fetchPositions() supports linear and inverse contracts only')
8430
8535
  result = self.parse_account_positions(response)
@@ -8437,8 +8542,11 @@ class binance(Exchange, ImplicitAPI):
8437
8542
  fetch positions risk
8438
8543
  :see: https://binance-docs.github.io/apidocs/futures/en/#position-information-v2-user_data
8439
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
8440
8547
  :param str[]|None symbols: list of unified market symbols
8441
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
8442
8550
  :returns dict: data on the positions risk
8443
8551
  """
8444
8552
  if symbols is not None:
@@ -8452,68 +8560,117 @@ class binance(Exchange, ImplicitAPI):
8452
8560
  type = self.safe_string(params, 'type', defaultType)
8453
8561
  subType = None
8454
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)
8455
8565
  params = self.omit(params, 'type')
8456
8566
  response = None
8457
8567
  if self.is_linear(type, subType):
8458
- response = await self.fapiPrivateV2GetPositionRisk(self.extend(request, params))
8459
- # ### Response examples ###
8460
- #
8461
- # For One-way position mode:
8462
- # [
8463
- # {
8464
- # "entryPrice": "0.00000",
8465
- # "marginType": "isolated",
8466
- # "isAutoAddMargin": "false",
8467
- # "isolatedMargin": "0.00000000",
8468
- # "leverage": "10",
8469
- # "liquidationPrice": "0",
8470
- # "markPrice": "6679.50671178",
8471
- # "maxNotionalValue": "20000000",
8472
- # "positionAmt": "0.000",
8473
- # "symbol": "BTCUSDT",
8474
- # "unRealizedProfit": "0.00000000",
8475
- # "positionSide": "BOTH",
8476
- # "updateTime": 0
8477
- # }
8478
- # ]
8479
- #
8480
- # For Hedge position mode:
8481
- # [
8482
- # {
8483
- # "entryPrice": "6563.66500",
8484
- # "marginType": "isolated",
8485
- # "isAutoAddMargin": "false",
8486
- # "isolatedMargin": "15517.54150468",
8487
- # "leverage": "10",
8488
- # "liquidationPrice": "5930.78",
8489
- # "markPrice": "6679.50671178",
8490
- # "maxNotionalValue": "20000000",
8491
- # "positionAmt": "20.000",
8492
- # "symbol": "BTCUSDT",
8493
- # "unRealizedProfit": "2316.83423560"
8494
- # "positionSide": "LONG",
8495
- # "updateTime": 1625474304765
8496
- # },
8497
- # {
8498
- # "entryPrice": "0.00000",
8499
- # "marginType": "isolated",
8500
- # "isAutoAddMargin": "false",
8501
- # "isolatedMargin": "5413.95799991",
8502
- # "leverage": "10",
8503
- # "liquidationPrice": "7189.95",
8504
- # "markPrice": "6679.50671178",
8505
- # "maxNotionalValue": "20000000",
8506
- # "positionAmt": "-10.000",
8507
- # "symbol": "BTCUSDT",
8508
- # "unRealizedProfit": "-1156.46711780",
8509
- # "positionSide": "SHORT",
8510
- # "updateTime": 0
8511
- # }
8512
- # ]
8568
+ if isPortfolioMargin:
8569
+ response = await self.papiGetUmPositionRisk(self.extend(request, params))
8570
+ else:
8571
+ response = await self.fapiPrivateV2GetPositionRisk(self.extend(request, params))
8513
8572
  elif self.is_inverse(type, subType):
8514
- 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))
8515
8577
  else:
8516
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
+ #
8517
8674
  result = []
8518
8675
  for i in range(0, len(response)):
8519
8676
  parsed = self.parse_position_risk(response[i])
@@ -8526,10 +8683,14 @@ class binance(Exchange, ImplicitAPI):
8526
8683
  fetch the history of funding payments paid and received on self account
8527
8684
  :see: https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data
8528
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
8529
8688
  :param str symbol: unified market symbol
8530
8689
  :param int [since]: the earliest time in ms to fetch funding history for
8531
8690
  :param int [limit]: the maximum number of funding history structures to retrieve
8532
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
8533
8694
  :returns dict: a `funding history structure <https://docs.ccxt.com/#/?id=funding-history-structure>`
8534
8695
  """
8535
8696
  await self.load_markets()
@@ -8544,6 +8705,9 @@ class binance(Exchange, ImplicitAPI):
8544
8705
  raise NotSupported(self.id + ' fetchFundingHistory() supports swap contracts only')
8545
8706
  subType = None
8546
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)
8547
8711
  if since is not None:
8548
8712
  request['startTime'] = since
8549
8713
  if limit is not None:
@@ -8553,9 +8717,15 @@ class binance(Exchange, ImplicitAPI):
8553
8717
  params = self.omit(params, 'type')
8554
8718
  response = None
8555
8719
  if self.is_linear(type, subType):
8556
- 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))
8557
8724
  elif self.is_inverse(type, subType):
8558
- 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))
8559
8729
  else:
8560
8730
  raise NotSupported(self.id + ' fetchFundingHistory() supports linear and inverse contracts only')
8561
8731
  return self.parse_incomes(response, market, since, limit)
@@ -8878,12 +9048,15 @@ class binance(Exchange, ImplicitAPI):
8878
9048
  :see: https://binance-docs.github.io/apidocs/voptions/en/#account-funding-flow-user_data
8879
9049
  :see: https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data
8880
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
8881
9053
  :param str code: unified currency code
8882
9054
  :param int [since]: timestamp in ms of the earliest ledger entry
8883
9055
  :param int [limit]: max number of ledger entrys to return
8884
9056
  :param dict [params]: extra parameters specific to the exchange API endpoint
8885
9057
  :param int [params.until]: timestamp in ms of the latest ledger entry
8886
- :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
8887
9060
  :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
8888
9061
  """
8889
9062
  await self.load_markets()
@@ -8907,15 +9080,23 @@ class binance(Exchange, ImplicitAPI):
8907
9080
  if until is not None:
8908
9081
  params = self.omit(params, 'until')
8909
9082
  request['endTime'] = until
9083
+ isPortfolioMargin = None
9084
+ isPortfolioMargin, params = self.handle_option_and_params_2(params, 'fetchLedger', 'papi', 'portfolioMargin', False)
8910
9085
  response = None
8911
9086
  if type == 'option':
8912
9087
  self.check_required_argument('fetchLedger', code, 'code')
8913
9088
  request['currency'] = currency['id']
8914
9089
  response = await self.eapiPrivateGetBill(self.extend(request, params))
8915
9090
  elif self.is_linear(type, subType):
8916
- 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))
8917
9095
  elif self.is_inverse(type, subType):
8918
- 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))
8919
9100
  else:
8920
9101
  raise NotSupported(self.id + ' fetchLedger() supports contract wallets only')
8921
9102
  #
@@ -8931,7 +9112,7 @@ class binance(Exchange, ImplicitAPI):
8931
9112
  # }
8932
9113
  # ]
8933
9114
  #
8934
- # futures(fapi, dapi)
9115
+ # futures(fapi, dapi, papi)
8935
9116
  #
8936
9117
  # [
8937
9118
  # {
@@ -8960,7 +9141,7 @@ class binance(Exchange, ImplicitAPI):
8960
9141
  # "createDate": 1676621042489
8961
9142
  # }
8962
9143
  #
8963
- # futures(fapi, dapi)
9144
+ # futures(fapi, dapi, papi)
8964
9145
  #
8965
9146
  # {
8966
9147
  # "symbol": "",
@@ -9059,7 +9240,7 @@ class binance(Exchange, ImplicitAPI):
9059
9240
  isSpotOrMargin = (api.find('sapi') > -1 or api == 'private')
9060
9241
  marketType = 'spot' if isSpotOrMargin else 'future'
9061
9242
  defaultId = 'x-xcKtGhcu' if (not isSpotOrMargin) else 'x-R4BD3S82'
9062
- broker = self.safe_value(self.options, 'broker', {})
9243
+ broker = self.safe_dict(self.options, 'broker', {})
9063
9244
  brokerId = self.safe_string(broker, marketType, defaultId)
9064
9245
  params['newClientOrderId'] = brokerId + self.uuid22()
9065
9246
  query = None
@@ -9081,8 +9262,8 @@ class binance(Exchange, ImplicitAPI):
9081
9262
  query = self.urlencode_with_array_repeat(extendedParams)
9082
9263
  elif (path == 'batchOrders') or (path.find('sub-account') >= 0) or (path == 'capital/withdraw/apply') or (path.find('staking') >= 0):
9083
9264
  if (method == 'DELETE') and (path == 'batchOrders'):
9084
- orderidlist = self.safe_value(extendedParams, 'orderidlist', [])
9085
- origclientorderidlist = self.safe_value(extendedParams, 'origclientorderidlist', [])
9265
+ orderidlist = self.safe_list(extendedParams, 'orderidlist', [])
9266
+ origclientorderidlist = self.safe_list(extendedParams, 'origclientorderidlist', [])
9086
9267
  extendedParams = self.omit(extendedParams, ['orderidlist', 'origclientorderidlist'])
9087
9268
  query = self.rawencode(extendedParams)
9088
9269
  orderidlistLength = len(orderidlist)
@@ -9131,8 +9312,8 @@ class binance(Exchange, ImplicitAPI):
9131
9312
  elif url.startswith('https://papi.' + hostname + '/'):
9132
9313
  marketType = 'portfoliomargin'
9133
9314
  if marketType is not None:
9134
- exceptionsForMarketType = self.safe_value(self.exceptions, marketType, {})
9135
- return self.safe_value(exceptionsForMarketType, exactOrBroad, {})
9315
+ exceptionsForMarketType = self.safe_dict(self.exceptions, marketType, {})
9316
+ return self.safe_dict(exceptionsForMarketType, exactOrBroad, {})
9136
9317
  return {}
9137
9318
 
9138
9319
  def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
@@ -9328,7 +9509,7 @@ class binance(Exchange, ImplicitAPI):
9328
9509
  # },
9329
9510
  # ]
9330
9511
  #
9331
- rate = self.safe_value(response, 0)
9512
+ rate = self.safe_dict(response, 0)
9332
9513
  return self.parse_borrow_rate(rate)
9333
9514
 
9334
9515
  async def fetch_borrow_rate_history(self, code: str, since: Int = None, limit: Int = None, params={}):
@@ -9424,7 +9605,7 @@ class binance(Exchange, ImplicitAPI):
9424
9605
  # "success": True
9425
9606
  # }
9426
9607
  #
9427
- data = self.safe_value(response, 'data')
9608
+ data = self.safe_dict(response, 'data')
9428
9609
  giftcardCode = self.safe_string(data, 'code')
9429
9610
  id = self.safe_string(data, 'referenceNo')
9430
9611
  return {
@@ -9523,7 +9704,7 @@ class binance(Exchange, ImplicitAPI):
9523
9704
  # "total": 1
9524
9705
  # }
9525
9706
  #
9526
- rows = self.safe_value(response, 'rows')
9707
+ rows = self.safe_list(response, 'rows')
9527
9708
  interest = self.parse_borrow_interests(rows, market)
9528
9709
  return self.filter_by_currency_since_limit(interest, code, since, limit)
9529
9710
 
@@ -9548,9 +9729,11 @@ class binance(Exchange, ImplicitAPI):
9548
9729
  """
9549
9730
  repay borrowed margin and interest
9550
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
9551
9733
  :param str code: unified currency code of the currency to repay
9552
9734
  :param float amount: the amount to repay
9553
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
9554
9737
  :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
9555
9738
  """
9556
9739
  await self.load_markets()
@@ -9558,10 +9741,16 @@ class binance(Exchange, ImplicitAPI):
9558
9741
  request = {
9559
9742
  'asset': currency['id'],
9560
9743
  'amount': self.currency_to_precision(code, amount),
9561
- 'isIsolated': 'FALSE',
9562
- 'type': 'REPAY',
9563
9744
  }
9564
- 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))
9565
9754
  #
9566
9755
  # {
9567
9756
  # "tranId": 108988250265,
@@ -9603,9 +9792,11 @@ class binance(Exchange, ImplicitAPI):
9603
9792
  """
9604
9793
  create a loan to borrow margin
9605
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
9606
9796
  :param str code: unified currency code of the currency to borrow
9607
9797
  :param float amount: the amount to borrow
9608
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
9609
9800
  :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
9610
9801
  """
9611
9802
  await self.load_markets()
@@ -9613,10 +9804,16 @@ class binance(Exchange, ImplicitAPI):
9613
9804
  request = {
9614
9805
  'asset': currency['id'],
9615
9806
  'amount': self.currency_to_precision(code, amount),
9616
- 'isIsolated': 'FALSE',
9617
- 'type': 'BORROW',
9618
9807
  }
9619
- 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))
9620
9817
  #
9621
9818
  # {
9622
9819
  # "tranId": 108988250265,