text: # -*- coding: utf-8 -*-
  
  # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
  
  from ccxt.base.exchange import Exchange
  import json
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import PermissionDenied
  from ccxt.base.errors import AccountSuspended
  from ccxt.base.errors import ArgumentsRequired
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import BadSymbol
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import OrderImmediatelyFillable
  from ccxt.base.errors import NotSupported
  from ccxt.base.errors import DDoSProtection
  from ccxt.base.errors import RateLimitExceeded
  from ccxt.base.errors import ExchangeNotAvailable
  from ccxt.base.errors import OnMaintenance
  from ccxt.base.errors import InvalidNonce
  from ccxt.base.decimal_to_precision import TRUNCATE
  from ccxt.base.precise import Precise
  
  
  class binance(Exchange):
  
      def describe(self):
          return self.deep_extend(super(binance, self).describe(), {
              'id': 'binance',
              'name': 'Binance',
              'countries': ['JP', 'MT'],  # Japan, Malta
              'rateLimit': 50,
              'certified': True,
              'pro': True,
              # new metainfo interface
              'has': {
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'CORS': None,
                  'createOrder': True,
                  'fetchBalance': True,
                  'fetchBidsAsks': True,
                  'fetchClosedOrders': 'emulated',
                  'fetchCurrencies': True,
                  'fetchDepositAddress': True,
                  'fetchDeposits': True,
                  'fetchFundingFees': True,
                  'fetchFundingHistory': True,
                  'fetchFundingRate': True,
                  'fetchFundingRateHistory': True,
                  'fetchFundingRates': True,
                  'fetchIndexOHLCV': True,
                  'fetchIsolatedPositions': True,
                  'fetchMarkets': True,
                  'fetchMarkOHLCV': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchOrders': True,
                  'fetchPositions': True,
                  'fetchPremiumIndexOHLCV': False,
                  'fetchStatus': True,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTime': True,
                  'fetchTrades': True,
                  'fetchTradingFee': True,
                  'fetchTradingFees': True,
                  'fetchTransactions': False,
                  'fetchTransfers': True,
                  'fetchWithdrawals': True,
                  'setLeverage': True,
                  'setMarginMode': True,
                  'setPositionMode': True,
                  'addMargin': True,
                  'reduceMargin': True,
                  'transfer': True,
                  'withdraw': True,
              },
              'timeframes': {
                  '1m': '1m',
                  '3m': '3m',
                  '5m': '5m',
                  '15m': '15m',
                  '30m': '30m',
                  '1h': '1h',
                  '2h': '2h',
                  '4h': '4h',
                  '6h': '6h',
                  '8h': '8h',
                  '12h': '12h',
                  '1d': '1d',
                  '3d': '3d',
                  '1w': '1w',
                  '1M': '1M',
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/29604020-d5483cdc-87ee-11e7-94c7-d1a8d9169293.jpg',
                  'test': {
                      'dapiPublic': 'https://testnet.binancefuture.com/dapi/v1',
                      'dapiPrivate': 'https://testnet.binancefuture.com/dapi/v1',
                      'fapiPublic': 'https://testnet.binancefuture.com/fapi/v1',
                      'fapiPrivate': 'https://testnet.binancefuture.com/fapi/v1',
                      'fapiPrivateV2': 'https://testnet.binancefuture.com/fapi/v2',
                      'public': 'https://testnet.binance.vision/api/v3',
                      'private': 'https://testnet.binance.vision/api/v3',
                      'v1': 'https://testnet.binance.vision/api/v1',
                  },
                  'api': {
                      'wapi': 'https://api.binance.com/wapi/v3',
                      'sapi': 'https://api.binance.com/sapi/v1',
                      'dapiPublic': 'https://dapi.binance.com/dapi/v1',
                      'dapiPrivate': 'https://dapi.binance.com/dapi/v1',
                      'dapiPrivateV2': 'https://dapi.binance.com/dapi/v2',
                      'dapiData': 'https://dapi.binance.com/futures/data',
                      'fapiPublic': 'https://fapi.binance.com/fapi/v1',
                      'fapiPrivate': 'https://fapi.binance.com/fapi/v1',
                      'fapiData': 'https://fapi.binance.com/futures/data',
                      'fapiPrivateV2': 'https://fapi.binance.com/fapi/v2',
                      'public': 'https://api.binance.com/api/v3',
                      'private': 'https://api.binance.com/api/v3',
                      'v1': 'https://api.binance.com/api/v1',
                  },
                  'www': 'https://www.binance.com',
                  # 'referral': {
                  #     'url': 'https://www.binance.com/en/register?ref=BLEJC98C',
                  #     'discount': 0.2,
                  # },
                  'doc': [
                      'https://binance-docs.github.io/apidocs/spot/en',
                  ],
                  'api_management': 'https://www.binance.com/en/usercenter/settings/api-management',
                  'fees': 'https://www.binance.com/en/fee/schedule',
              },
              'depth': 1,
              'api': {
                  # the API structure below will need 3-layer apidefs
                  'sapi': {
                      'get': {
                          'accountSnapshot': 1,
                          'system/status': 1,
                          # these endpoints require self.apiKey
                          'margin/asset': 1,
                          'margin/pair': 1,
                          'margin/allAssets': 1,
                          'margin/allPairs': 1,
                          'margin/priceIndex': 1,
                          # these endpoints require self.apiKey + self.secret
                          'asset/assetDividend': 1,
                          'asset/dribblet': 1,
                          'asset/transfer': 1,
                          'asset/assetDetail': 1,
                          'asset/tradeFee': 1,
                          'asset/get-funding-asset': 1,
                          'margin/loan': 1,
                          'margin/repay': 1,
                          'margin/account': 1,
                          'margin/transfer': 1,
                          'margin/interestHistory': 1,
                          'margin/forceLiquidationRec': 1,
                          'margin/order': 1,
                          'margin/openOrders': 1,
                          'margin/allOrders': 1,
                          'margin/myTrades': 1,
                          'margin/maxBorrowable': 5,
                          'margin/maxTransferable': 5,
                          'margin/isolated/transfer': 1,
                          'margin/isolated/account': 1,
                          'margin/isolated/pair': 1,
                          'margin/isolated/allPairs': 1,
                          'margin/isolated/accountLimit': 1,
                          'margin/interestRateHistory': 1,
                          'margin/orderList': 2,
                          'margin/allOrderList': 10,
                          'margin/openOrderList': 3,
                          'loan/income': 1,
                          'fiat/orders': 1,
                          'fiat/payments': 1,
                          'futures/transfer': 5,
                          'futures/loan/borrow/history': 1,
                          'futures/loan/repay/history': 1,
                          'futures/loan/wallet': 1,
                          'futures/loan/configs': 1,
                          'futures/loan/calcAdjustLevel': 1,
                          'futures/loan/calcMaxAdjustAmount': 1,
                          'futures/loan/adjustCollateral/history': 1,
                          'futures/loan/liquidationHistory': 1,
                          # https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi
                          'capital/config/getall': 1,  # get networks for withdrawing USDT ERC20 vs USDT Omni
                          'capital/deposit/address': 1,
                          'capital/deposit/hisrec': 1,
                          'capital/deposit/subAddress': 1,
                          'capital/deposit/subHisrec': 1,
                          'capital/withdraw/history': 1,
                          'account/status': 1,
                          'account/apiTradingStatus': 1,
                          'account/apiRestrictions/ipRestriction': 1,
                          'bnbBurn': 1,
                          'sub-account/assets': 1,
                          'sub-account/futures/account': 1,
                          'sub-account/futures/accountSummary': 1,
                          'sub-account/futures/positionRisk': 1,
                          'sub-account/futures/internalTransfer': 1,
                          'sub-account/list': 1,
                          'sub-account/margin/account': 1,
                          'sub-account/margin/accountSummary': 1,
                          'sub-account/spotSummary': 5,
                          'sub-account/status': 1,
                          'sub-account/sub/transfer/history': 1,
                          'sub-account/transfer/subUserHistory': 1,
                          'sub-account/universalTransfer': 1,
                          # lending endpoints
                          'lending/daily/product/list': 1,
                          'lending/daily/userLeftQuota': 1,
                          'lending/daily/userRedemptionQuota': 1,
                          'lending/daily/token/position': 1,
                          'lending/union/account': 1,
                          'lending/union/purchaseRecord': 1,
                          'lending/union/redemptionRecord': 1,
                          'lending/union/interestHistory': 1,
                          'lending/project/list': 1,
                          'lending/project/position/list': 1,
                          # mining endpoints
                          'mining/pub/algoList': 1,
                          'mining/pub/coinList': 1,
                          'mining/worker/detail': 5,
                          'mining/worker/list': 5,
                          'mining/payment/list': 5,
                          'mining/statistics/user/status': 5,
                          'mining/statistics/user/list': 5,
                          # liquid swap endpoints
                          'bswap/pools': 1,
                          'bswap/liquidity': {'cost': 1, 'noPoolId': 10},
                          'bswap/liquidityOps': 2,
                          'bswap/quote': 2,
                          'bswap/swap': 1,
                          'bswap/poolConfigure': 1,
                          'bswap/addLiquidityPreview': 1,
                          'bswap/removeLiquidityPreview': 1,
                          # leveraged token endpoints
                          'blvt/tokenInfo': 1,
                          'blvt/subscribe/record': 1,
                          'blvt/redeem/record': 1,
                          'blvt/userLimit': 1,
                          # broker api
                          'apiReferral/ifNewUser': 1,
                          'apiReferral/customization': 1,
                          'apiReferral/userCustomization': 1,
                          'apiReferral/rebate/recentRecord': 1,
                          'apiReferral/rebate/historicalRecord': 1,
                          'apiReferral/kickback/recentRecord': 1,
                          'apiReferral/kickback/historicalRecord': 1,
                          # brokerage API
                          'broker/subAccountApi': 1,
                          'broker/subAccount': 1,
                          'broker/subAccountApi/commission/futures': 1,
                          'broker/subAccountApi/commission/coinFutures': 1,
                          'broker/info': 1,
                          'broker/transfer': 1,
                          'broker/transfer/futures': 1,
                          'broker/rebate/recentRecord': 1,
                          'broker/rebate/historicalRecord': 1,
                          'broker/subAccount/bnbBurn/status': 1,
                          'broker/subAccount/depositHist': 1,
                          'broker/subAccount/spotSummary': 1,
                          'broker/subAccount/marginSummary': 1,
                          'broker/subAccount/futuresSummary': 1,
                          'broker/rebate/futures/recentRecord': 1,
                          'broker/subAccountApi/ipRestriction': 1,
                          'broker/universalTransfer': 1,
                          # v2 not supported yet
                          # GET /sapi/v2/broker/subAccount/futuresSummary
                          'account/apiRestrictions': 1,
                          # subaccounts
                          'managed-subaccount/asset': 1,
                      },
                      'post': {
                          'asset/dust': 1,
                          'asset/transfer': 1,
                          'asset/get-funding-asset': 1,
                          'account/disableFastWithdrawSwitch': 1,
                          'account/enableFastWithdrawSwitch': 1,
                          'account/apiRestrictions/ipRestriction': 1,
                          'account/apiRestrictions/ipRestriction/ipList': 1,
                          'capital/withdraw/apply': 1,
                          'margin/transfer': 1,
                          'margin/loan': 1,
                          'margin/repay': 1,
                          'margin/order': 4,
                          'margin/order/oco': 1,
                          'margin/isolated/create': 1,
                          'margin/isolated/transfer': 1,
                          'margin/isolated/account': 1,
                          'bnbBurn': 1,
                          'sub-account/margin/transfer': 1,
                          'sub-account/margin/enable': 1,
                          # 'sub-account/margin/enable': 1,
                          'sub-account/futures/enable': 1,
                          'sub-account/futures/transfer': 1,
                          'sub-account/futures/internalTransfer': 1,
                          'sub-account/transfer/subToSub': 1,
                          'sub-account/transfer/subToMaster': 1,
                          'sub-account/universalTransfer': 1,
                          'managed-subaccount/deposit': 1,
                          'managed-subaccount/withdraw': 1,
                          'userDataStream': 1,
                          'userDataStream/isolated': 1,
                          'futures/transfer': 1,
                          'futures/loan/borrow': 20,
                          'futures/loan/repay': 20,
                          'futures/loan/adjustCollateral': 20,
                          # lending
                          'lending/customizedFixed/purchase': 1,
                          'lending/daily/purchase': 1,
                          'lending/daily/redeem': 1,
                          # liquid swap endpoints
                          'bswap/liquidityAdd': 2,
                          'bswap/liquidityRemove': 2,
                          'bswap/swap': 2,
                          # leveraged token endpoints
                          'blvt/subscribe': 1,
                          'blvt/redeem': 1,
                          # brokerage API
                          'apiReferral/customization': 1,
                          'apiReferral/userCustomization': 1,
                          'apiReferral/rebate/historicalRecord': 1,
                          'apiReferral/kickback/historicalRecord': 1,
                          'broker/subAccount': 1,
                          'broker/subAccount/margin': 1,
                          'broker/subAccount/futures': 1,
                          'broker/subAccountApi': 1,
                          'broker/subAccountApi/permission': 1,
                          'broker/subAccountApi/commission': 1,
                          'broker/subAccountApi/commission/futures': 1,
                          'broker/subAccountApi/commission/coinFutures': 1,
                          'broker/transfer': 1,
                          'broker/transfer/futures': 1,
                          'broker/rebate/historicalRecord': 1,
                          'broker/subAccount/bnbBurn/spot': 1,
                          'broker/subAccount/bnbBurn/marginInterest': 1,
                          'broker/subAccount/blvt': 1,
                          'broker/subAccountApi/ipRestriction': 1,
                          'broker/subAccountApi/ipRestriction/ipList': 1,
                          'broker/universalTransfer': 1,
                          'broker/subAccountApi/permission/universalTransfer': 1,
                          'broker/subAccountApi/permission/vanillaOptions': 1,
                      },
                      'put': {
                          'userDataStream': 1,
                          'userDataStream/isolated': 1,
                      },
                      'delete': {
                          'account/apiRestrictions/ipRestriction/ipList': 1,
                          'margin/openOrders': 1,
                          'margin/order': 1,
                          'margin/orderList': 1,
                          'margin/isolated/account': 1,
                          'userDataStream': 1,
                          'userDataStream/isolated': 1,
                          # brokerage API
                          'broker/subAccountApi': 1,
                          'broker/subAccountApi/ipRestriction/ipList': 1,
                      },
                  },
                  # deprecated
                  'wapi': {
                      'post': {
                          'withdraw': 1,
                          'sub-account/transfer': 1,
                      },
                      'get': {
                          'depositHistory': 1,
                          'withdrawHistory': 1,
                          'depositAddress': 1,
                          'accountStatus': 1,
                          'systemStatus': 1,
                          'apiTradingStatus': 1,
                          'userAssetDribbletLog': 1,
                          'tradeFee': 1,
                          'assetDetail': 1,
                          'sub-account/list': 1,
                          'sub-account/transfer/history': 1,
                          'sub-account/assets': 1,
                      },
                  },
                  'dapiPublic': {
                      'get': {
                          'ping': 1,
                          'time': 1,
                          'exchangeInfo': 1,
                          'depth': {'cost': 2, 'byLimit': [[50, 2], [100, 5], [500, 10], [1000, 20]]},
                          'trades': 1,
                          'historicalTrades': 20,
                          'aggTrades': 20,
                          'premiumIndex': 10,
                          'fundingRate': 1,
                          'klines': {'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]]},
                          'continuousKlines': {'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]]},
                          'indexPriceKlines': {'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]]},
                          'markPriceKlines': {'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]]},
                          'ticker/24hr': {'cost': 1, 'noSymbol': 40},
                          'ticker/price': {'cost': 1, 'noSymbol': 2},
                          'ticker/bookTicker': {'cost': 1, 'noSymbol': 2},
                          'openInterest': 1,
                      },
                  },
                  'dapiData': {
                      'get': {
                          'openInterestHist': 1,
                          'topLongShortAccountRatio': 1,
                          'topLongShortPositionRatio': 1,
                          'globalLongShortAccountRatio': 1,
                          'takerBuySellVol': 1,
                          'basis': 1,
                      },
                  },
                  'dapiPrivate': {
                      'get': {
                          'positionSide/dual': 30,
                          'order': 1,
                          'openOrder': 1,
                          'openOrders': {'cost': 1, 'noSymbol': 5},
                          'allOrders': {'cost': 20, 'noSymbol': 40},
                          'balance': 1,
                          'account': 5,
                          'positionMargin/history': 1,
                          'positionRisk': 1,
                          'userTrades': {'cost': 20, 'noSymbol': 40},
                          'income': 20,
                          'leverageBracket': 1,
                          'forceOrders': {'cost': 20, 'noSymbol': 50},
                          'adlQuantile': 5,
                      },
                      'post': {
                          'positionSide/dual': 1,
                          'order': 4,
                          'batchOrders': 5,
                          'countdownCancelAll': 10,
                          'leverage': 1,
                          'marginType': 1,
                          'positionMargin': 1,
                          'listenKey': 1,
                      },
                      'put': {
                          'listenKey': 1,
                      },
                      'delete': {
                          'order': 1,
                          'allOpenOrders': 1,
                          'batchOrders': 5,
                          'listenKey': 1,
                      },
                  },
                  'dapiPrivateV2': {
                      'get': {
                          'leverageBracket': 1,
                      },
                  },
                  'fapiPublic': {
                      'get': {
                          'ping': 1,
                          'time': 1,
                          'exchangeInfo': 1,
                          'depth': {'cost': 2, 'byLimit': [[50, 2], [100, 5], [500, 10], [1000, 20]]},
                          'trades': 1,
                          'historicalTrades': 20,
                          'aggTrades': 20,
                          'klines': {'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]]},
                          'continuousKlines': {'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]]},
                          'markPriceKlines': {'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]]},
                          'indexPriceKlines': {'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]]},
                          'fundingRate': 1,
                          'premiumIndex': 1,
                          'ticker/24hr': {'cost': 1, 'noSymbol': 40},
                          'ticker/price': {'cost': 1, 'noSymbol': 2},
                          'ticker/bookTicker': {'cost': 1, 'noSymbol': 2},
                          'openInterest': 1,
                          'indexInfo': 1,
                          'apiTradingStatus': {'cost': 1, 'noSymbol': 10},
                          'lvtKlines': 1,
                      },
                  },
                  'fapiData': {
                      'get': {
                          'openInterestHist': 1,
                          'topLongShortAccountRatio': 1,
                          'topLongShortPositionRatio': 1,
                          'globalLongShortAccountRatio': 1,
                          'takerlongshortRatio': 1,
                      },
                  },
                  'fapiPrivate': {
                      'get': {
                          'forceOrders': {'cost': 20, 'noSymbol': 50},
                          'allOrders': 5,
                          'openOrder': 1,
                          'openOrders': 1,
                          'order': 1,
                          'account': 5,
                          'balance': 5,
                          'leverageBracket': 1,
                          'positionMargin/history': 1,
                          'positionRisk': 5,
                          'positionSide/dual': 30,
                          'userTrades': 5,
                          'income': 30,
                          'commissionRate': 20,
                          'apiTradingStatus': 1,
                          'multiAssetsMargin': 30,
                          # broker endpoints
                          'apiReferral/ifNewUser': 1,
                          'apiReferral/customization': 1,
                          'apiReferral/userCustomization': 1,
                          'apiReferral/traderNum': 1,
                          'apiReferral/overview': 1,
                          'apiReferral/tradeVol': 1,
                          'apiReferral/rebateVol': 1,
                          'apiReferral/traderSummary': 1,
                          'adlQuantile': 5,
                      },
                      'post': {
                          'batchOrders': 5,
                          'positionSide/dual': 1,
                          'positionMargin': 1,
                          'marginType': 1,
                          'order': 4,
                          'leverage': 1,
                          'listenKey': 1,
                          'countdownCancelAll': 10,
                          'multiAssetsMargin': 1,
                          # broker endpoints
                          'apiReferral/customization': 1,
                          'apiReferral/userCustomization': 1,
                      },
                      'put': {
                          'listenKey': 1,
                      },
                      'delete': {
                          'batchOrders': 1,
                          'order': 1,
                          'allOpenOrders': 1,
                          'listenKey': 1,
                      },
                  },
                  'fapiPrivateV2': {
                      'get': {
                          'account': 1,
                          'balance': 1,
                          'positionRisk': 1,
                      },
                  },
                  'public': {
                      'get': {
                          'ping': 1,
                          'time': 1,
                          'depth': {'cost': 1, 'byLimit': [[100, 1], [500, 5], [1000, 10], [5000, 50]]},
                          'trades': 1,
                          'aggTrades': 1,
                          'historicalTrades': 5,
                          'klines': 1,
                          'ticker/24hr': {'cost': 1, 'noSymbol': 40},
                          'ticker/price': {'cost': 1, 'noSymbol': 2},
                          'ticker/bookTicker': {'cost': 1, 'noSymbol': 2},
                          'exchangeInfo': 10,
                      },
                      'put': {
                          'userDataStream': 1,
                      },
                      'post': {
                          'userDataStream': 1,
                      },
                      'delete': {
                          'userDataStream': 1,
                      },
                  },
                  'private': {
                      'get': {
                          'allOrderList': 10,  # oco
                          'openOrderList': 3,  # oco
                          'orderList': 2,  # oco
                          'order': 2,
                          'openOrders': {'cost': 3, 'noSymbol': 40},
                          'allOrders': 10,
                          'account': 10,
                          'myTrades': 10,
                          'rateLimit/order': 20,
                      },
                      'post': {
                          'order/oco': 1,
                          'order': 4,
                          'order/test': 1,
                      },
                      'delete': {
                          'openOrders': 1,  # added on 2020-04-25 for canceling all open orders per symbol
                          'orderList': 1,  # oco
                          'order': 1,
                      },
                  },
              },
              'fees': {
                  'trading': {
                      'feeSide': 'get',
                      'tierBased': False,
                      'percentage': True,
                      'taker': self.parse_number('0.001'),
                      'maker': self.parse_number('0.001'),
                  },
                  'future': {
                      'trading': {
                          'feeSide': 'quote',
                          'tierBased': True,
                          'percentage': True,
                          'taker': self.parse_number('0.000400'),
                          'maker': self.parse_number('0.000200'),
                          'tiers': {
                              'taker': [
                                  [self.parse_number('0'), self.parse_number('0.000400')],
                                  [self.parse_number('250'), self.parse_number('0.000400')],
                                  [self.parse_number('2500'), self.parse_number('0.000350')],
                                  [self.parse_number('7500'), self.parse_number('0.000320')],
                                  [self.parse_number('22500'), self.parse_number('0.000300')],
                                  [self.parse_number('50000'), self.parse_number('0.000270')],
                                  [self.parse_number('100000'), self.parse_number('0.000250')],
                                  [self.parse_number('200000'), self.parse_number('0.000220')],
                                  [self.parse_number('400000'), self.parse_number('0.000200')],
                                  [self.parse_number('750000'), self.parse_number('0.000170')],
                              ],
                              'maker': [
                                  [self.parse_number('0'), self.parse_number('0.000200')],
                                  [self.parse_number('250'), self.parse_number('0.000160')],
                                  [self.parse_number('2500'), self.parse_number('0.000140')],
                                  [self.parse_number('7500'), self.parse_number('0.000120')],
                                  [self.parse_number('22500'), self.parse_number('0.000100')],
                                  [self.parse_number('50000'), self.parse_number('0.000080')],
                                  [self.parse_number('100000'), self.parse_number('0.000060')],
                                  [self.parse_number('200000'), self.parse_number('0.000040')],
                                  [self.parse_number('400000'), self.parse_number('0.000020')],
                                  [self.parse_number('750000'), self.parse_number('0')],
                              ],
                          },
                      },
                  },
                  'delivery': {
                      'trading': {
                          'feeSide': 'base',
                          'tierBased': True,
                          'percentage': True,
                          'taker': self.parse_number('0.000500'),
                          'maker': self.parse_number('0.000100'),
                          'tiers': {
                              'taker': [
                                  [self.parse_number('0'), self.parse_number('0.000500')],
                                  [self.parse_number('250'), self.parse_number('0.000450')],
                                  [self.parse_number('2500'), self.parse_number('0.000400')],
                                  [self.parse_number('7500'), self.parse_number('0.000300')],
                                  [self.parse_number('22500'), self.parse_number('0.000250')],
                                  [self.parse_number('50000'), self.parse_number('0.000240')],
                                  [self.parse_number('100000'), self.parse_number('0.000240')],
                                  [self.parse_number('200000'), self.parse_number('0.000240')],
                                  [self.parse_number('400000'), self.parse_number('0.000240')],
                                  [self.parse_number('750000'), self.parse_number('0.000240')],
                              ],
                              'maker': [
                                  [self.parse_number('0'), self.parse_number('0.000100')],
                                  [self.parse_number('250'), self.parse_number('0.000080')],
                                  [self.parse_number('2500'), self.parse_number('0.000050')],
                                  [self.parse_number('7500'), self.parse_number('0.0000030')],
                                  [self.parse_number('22500'), self.parse_number('0')],
                                  [self.parse_number('50000'), self.parse_number('-0.000050')],
                                  [self.parse_number('100000'), self.parse_number('-0.000060')],
                                  [self.parse_number('200000'), self.parse_number('-0.000070')],
                                  [self.parse_number('400000'), self.parse_number('-0.000080')],
                                  [self.parse_number('750000'), self.parse_number('-0.000090')],
                              ],
                          },
                      },
                  },
              },
              'commonCurrencies': {
                  'BCC': 'BCC',  # kept for backward-compatibility https://github.com/ccxt/ccxt/issues/4848
                  'YOYO': 'YOYOW',
              },
              # exchange-specific options
              'options': {
                  'fetchCurrencies': True,  # self is a private call and it requires API keys
                  # 'fetchTradesMethod': 'publicGetAggTrades',  # publicGetTrades, publicGetHistoricalTrades
                  'defaultTimeInForce': 'GTC',  # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel
                  'defaultType': 'spot',  # 'spot', 'future', 'margin', 'delivery'
                  'hasAlreadyAuthenticatedSuccessfully': False,
                  'warnOnFetchOpenOrdersWithoutSymbol': True,
                  'fetchPositions': 'positionRisk',  # or 'account'
                  'recvWindow': 5 * 1000,  # 5 sec, binance default
                  'timeDifference': 0,  # the difference between system clock and Binance clock
                  'adjustForTimeDifference': False,  # controls the adjustment logic upon instantiation
                  'newOrderRespType': {
                      'market': 'FULL',  # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
                      'limit': 'FULL',  # we change it from 'ACK' by default to 'FULL'(returns immediately if limit is not hit)
                  },
                  'quoteOrderQty': True,  # whether market orders support amounts in quote currency
                  'broker': {
                      'spot': 'x-R4BD3S82',
                      'margin': 'x-R4BD3S82',
                      'future': 'x-xcKtGhcu',
                      'delivery': 'x-xcKtGhcu',
                  },
                  'accountsByType': {
                      'main': 'MAIN',
                      'spot': 'MAIN',
                      'funding': 'FUNDING',
                      'margin': 'MARGIN',
                      'future': 'UMFUTURE',
                      'delivery': 'CMFUTURE',
                      'mining': 'MINING',
                  },
                  'typesByAccount': {
                      'MAIN': 'spot',
                      'FUNDING': 'funding',
                      'MARGIN': 'margin',
                      'UMFUTURE': 'future',
                      'CMFUTURE': 'delivery',
                      'MINING': 'mining',
                  },
                  'networks': {
                      'ERC20': 'ETH',
                      'TRC20': 'TRX',
                      'BEP2': 'BNB',
                      'BEP20': 'BSC',
                      'OMNI': 'OMNI',
                      'EOS': 'EOS',
                      'SPL': 'SOL',
                  },
                  'reverseNetworks': {
                      'tronscan.org': 'TRC20',
                      'etherscan.io': 'ERC20',
                      'bscscan.com': 'BSC',
                      'explorer.binance.org': 'BEP2',
                      'bithomp.com': 'XRP',
                      'bloks.io': 'EOS',
                      'stellar.expert': 'XLM',
                      'blockchair.com/bitcoin': 'BTC',
                      'blockchair.com/bitcoin-cash': 'BCH',
                      'blockchair.com/ecash': 'XEC',
                      'explorer.litecoin.net': 'LTC',
                      'explorer.avax.network': 'AVAX',
                      'solscan.io': 'SOL',
                      'polkadot.subscan.io': 'DOT',
                      'dashboard.internetcomputer.org': 'ICP',
                      'explorer.chiliz.com': 'CHZ',
                      'cardanoscan.io': 'ADA',
                      'mainnet.theoan.com': 'AION',
                      'algoexplorer.io': 'ALGO',
                      'explorer.ambrosus.com': 'AMB',
                      'viewblock.io/zilliqa': 'ZIL',
                      'viewblock.io/arweave': 'AR',
                      'explorer.ark.io': 'ARK',
                      'atomscan.com': 'ATOM',
                      'www.mintscan.io': 'CTK',
                      'explorer.bitcoindiamond.org': 'BCD',
                      'btgexplorer.com': 'BTG',
                      'bts.ai': 'BTS',
                      'explorer.celo.org': 'CELO',
                      'explorer.nervos.org': 'CKB',
                      'cerebro.cortexlabs.ai': 'CTXC',
                      'chainz.cryptoid.info': 'VIA',
                      'explorer.dcrdata.org': 'DCR',
                      'digiexplorer.info': 'DGB',
                      'dock.subscan.io': 'DOCK',
                      'dogechain.info': 'DOGE',
                      'explorer.elrond.com': 'EGLD',
                      'blockscout.com': 'ETC',
                      'explore-fetchhub.fetch.ai': 'FET',
                      'filfox.info': 'FIL',
                      'fio.bloks.io': 'FIO',
                      'explorer.firo.org': 'FIRO',
                      'neoscan.io': 'NEO',
                      'ftmscan.com': 'FTM',
                      'explorer.gochain.io': 'GO',
                      'block.gxb.io': 'GXS',
                      'hash-hash.info': 'HBAR',
                      'www.hiveblockexplorer.com': 'HIVE',
                      'explorer.helium.com': 'HNT',
                      'tracker.icon.foundation': 'ICX',
                      'www.iostabc.com': 'IOST',
                      'explorer.iota.org': 'IOTA',
                      'iotexscan.io': 'IOTX',
                      'irishub.iobscan.io': 'IRIS',
                      'kava.mintscan.io': 'KAVA',
                      'scope.klaytn.com': 'KLAY',
                      'kmdexplorer.io': 'KMD',
                      'kusama.subscan.io': 'KSM',
                      'explorer.lto.network': 'LTO',
                      'polygonscan.com': 'POLYGON',
                      'explorer.ont.io': 'ONT',
                      'minaexplorer.com': 'MINA',
                      'nanolooker.com': 'NANO',
                      'explorer.nebulas.io': 'NAS',
                      'explorer.nbs.plus': 'NBS',
                      'explorer.nebl.io': 'NEBL',
                      'nulscan.io': 'NULS',
                      'nxscan.com': 'NXS',
                      'explorer.harmony.one': 'ONE',
                      'explorer.poa.network': 'POA',
                      'qtum.info': 'QTUM',
                      'explorer.rsk.co': 'RSK',
                      'www.oasisscan.com': 'ROSE',
                      'ravencoin.network': 'RVN',
                      'sc.tokenview.com': 'SC',
                      'secretnodes.com': 'SCRT',
                      'explorer.skycoin.com': 'SKY',
                      'steemscan.com': 'STEEM',
                      'explorer.stacks.co': 'STX',
                      'www.thetascan.io': 'THETA',
                      'scan.tomochain.com': 'TOMO',
                      'explore.vechain.org': 'VET',
                      'explorer.vite.net': 'VITE',
                      'www.wanscan.org': 'WAN',
                      'wavesexplorer.com': 'WAVES',
                      'wax.eosx.io': 'WAXP',
                      'waltonchain.pro': 'WTC',
                      'chain.nem.ninja': 'XEM',
                      'verge-blockchain.info': 'XVG',
                      'explorer.yoyow.org': 'YOYOW',
                      'explorer.zcha.in': 'ZEC',
                      'explorer.zensystem.io': 'ZEN',
                  },
                  'impliedNetworks': {
                      'ETH': {'ERC20': 'ETH'},
                      'TRX': {'TRC20': 'TRX'},
                  },
                  'legalMoney': {
                      'MXN': True,
                      'UGX': True,
                      'SEK': True,
                      'CHF': True,
                      'VND': True,
                      'AED': True,
                      'DKK': True,
                      'KZT': True,
                      'HUF': True,
                      'PEN': True,
                      'PHP': True,
                      'USD': True,
                      'TRY': True,
                      'EUR': True,
                      'NGN': True,
                      'PLN': True,
                      'BRL': True,
                      'ZAR': True,
                      'KES': True,
                      'ARS': True,
                      'RUB': True,
                      'AUD': True,
                      'NOK': True,
                      'CZK': True,
                      'GBP': True,
                      'UAH': True,
                      'GHS': True,
                      'HKD': True,
                      'CAD': True,
                      'INR': True,
                      'JPY': True,
                      'NZD': True,
                  },
              },
              # https://binance-docs.github.io/apidocs/spot/en/#error-codes-2
              'exceptions': {
                  'exact': {
                      'System is under maintenance.': OnMaintenance,  # {"code":1,"msg":"System is under maintenance."}
                      'System abnormality': ExchangeError,  # {"code":-1000,"msg":"System abnormality"}
                      'You are not authorized to execute self request.': PermissionDenied,  # {"msg":"You are not authorized to execute self request."}
                      'API key does not exist': AuthenticationError,
                      'Order would trigger immediately.': OrderImmediatelyFillable,
                      'Stop price would trigger immediately.': OrderImmediatelyFillable,  # {"code":-2010,"msg":"Stop price would trigger immediately."}
                      'Order would immediately match and take.': OrderImmediatelyFillable,  # {"code":-2010,"msg":"Order would immediately match and take."}
                      'Account has insufficient balance for requested action.': InsufficientFunds,
                      'Rest API trading is not enabled.': ExchangeNotAvailable,
                      "You don't have permission.": PermissionDenied,  # {"msg":"You don't have permission.","success":false}
                      'Market is closed.': ExchangeNotAvailable,  # {"code":-1013,"msg":"Market is closed."}
                      'Too many requests. Please try again later.': DDoSProtection,  # {"msg":"Too many requests. Please try again later.","success":false}
                      '-1000': ExchangeNotAvailable,  # {"code":-1000,"msg":"An unknown error occured while processing the request."}
                      '-1001': ExchangeNotAvailable,  # 'Internal error; unable to process your request. Please try again.'
                      '-1002': AuthenticationError,  # 'You are not authorized to execute self request.'
                      '-1003': RateLimitExceeded,  # {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."}
                      '-1013': InvalidOrder,  # createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL
                      '-1015': RateLimitExceeded,  # 'Too many new orders; current limit is %s orders per %s.'
                      '-1016': ExchangeNotAvailable,  # 'This service is no longer available.',
                      '-1020': BadRequest,  # 'This operation is not supported.'
                      '-1021': InvalidNonce,  # 'your time is ahead of server'
                      '-1022': AuthenticationError,  # {"code":-1022,"msg":"Signature for self request is not valid."}
                      '-1100': BadRequest,  # createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'
                      '-1101': BadRequest,  # Too many parameters; expected %s and received %s.
                      '-1102': BadRequest,  # Param %s or %s must be sent, but both were empty
                      '-1103': BadRequest,  # An unknown parameter was sent.
                      '-1104': BadRequest,  # Not all sent parameters were read, read 8 parameters but was sent 9
                      '-1105': BadRequest,  # Parameter %s was empty.
                      '-1106': BadRequest,  # Parameter %s sent when not required.
                      '-1111': BadRequest,  # Precision is over the maximum defined for self asset.
                      '-1112': InvalidOrder,  # No orders on book for symbol.
                      '-1114': BadRequest,  # TimeInForce parameter sent when not required.
                      '-1115': BadRequest,  # Invalid timeInForce.
                      '-1116': BadRequest,  # Invalid orderType.
                      '-1117': BadRequest,  # Invalid side.
                      '-1118': BadRequest,  # New client order ID was empty.
                      '-1119': BadRequest,  # Original client order ID was empty.
                      '-1120': BadRequest,  # Invalid interval.
                      '-1121': BadSymbol,  # Invalid symbol.
                      '-1125': AuthenticationError,  # This listenKey does not exist.
                      '-1127': BadRequest,  # More than %s hours between startTime and endTime.
                      '-1128': BadRequest,  # {"code":-1128,"msg":"Combination of optional parameters invalid."}
                      '-1130': BadRequest,  # Data sent for paramter %s is not valid.
                      '-1131': BadRequest,  # recvWindow must be less than 60000
                      '-2008': AuthenticationError,  # {"code":-2008,"msg":"Invalid Api-Key ID."}
                      '-2010': ExchangeError,  # generic error code for createOrder -> 'Account has insufficient balance for requested action.', {"code":-2010,"msg":"Rest API trading is not enabled."}, etc...
                      '-2011': OrderNotFound,  # cancelOrder(1, 'BTC/USDT') -> 'UNKNOWN_ORDER'
                      '-2013': OrderNotFound,  # fetchOrder(1, 'BTC/USDT') -> 'Order does not exist'
                      '-2014': AuthenticationError,  # {"code":-2014, "msg": "API-key format invalid."}
                      '-2015': AuthenticationError,  # "Invalid API-key, IP, or permissions for action."
                      '-2019': InsufficientFunds,  # {"code":-2019,"msg":"Margin is insufficient."}
                      '-3005': InsufficientFunds,  # {"code":-3005,"msg":"Transferring out not allowed. Transfer out amount exceeds max amount."}
                      '-3006': InsufficientFunds,  # {"code":-3006,"msg":"Your borrow amount has exceed maximum borrow amount."}
                      '-3008': InsufficientFunds,  # {"code":-3008,"msg":"Borrow not allowed. Your borrow amount has exceed maximum borrow amount."}
                      '-3010': ExchangeError,  # {"code":-3010,"msg":"Repay not allowed. Repay amount exceeds borrow amount."}
                      '-3015': ExchangeError,  # {"code":-3015,"msg":"Repay amount exceeds borrow amount."}
                      '-3022': AccountSuspended,  # You account's trading is banned.
                      '-4028': BadRequest,  # {"code":-4028,"msg":"Leverage 100 is not valid"}
                      '-3020': InsufficientFunds,  # {"code":-3020,"msg":"Transfer out amount exceeds max amount."}
                      '-3041': InsufficientFunds,  # {"code":-3041,"msg":"Balance is not enough"}
                      '-5013': InsufficientFunds,  # Asset transfer failed: insufficient balance"
                      '-11008': InsufficientFunds,  # {"code":-11008,"msg":"Exceeding the account's maximum borrowable limit."}
                      '-4051': InsufficientFunds,  # {"code":-4051,"msg":"Isolated balance insufficient."}
                  },
                  'broad': {
                      'has no operation privilege': PermissionDenied,
                      'MAX_POSITION': InvalidOrder,  # {"code":-2010,"msg":"Filter failure: MAX_POSITION"}
                  },
              },
          })
  
      def cost_to_precision(self, symbol, cost):
          return self.decimal_to_precision(cost, TRUNCATE, self.markets[symbol]['precision']['quote'], self.precisionMode, self.paddingMode)
  
      def currency_to_precision(self, currency, fee):
          # info is available in currencies only if the user has configured his api keys
          if self.safe_value(self.currencies[currency], 'precision') is not None:
              return self.decimal_to_precision(fee, TRUNCATE, self.currencies[currency]['precision'], self.precisionMode, self.paddingMode)
          else:
              return self.number_to_string(fee)
  
      def nonce(self):
          return self.milliseconds() - self.options['timeDifference']
  
      def fetch_time(self, params={}):
          defaultType = self.safe_string_2(self.options, 'fetchTime', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          query = self.omit(params, 'type')
          method = 'publicGetTime'
          if type == 'future':
              method = 'fapiPublicGetTime'
          elif type == 'delivery':
              method = 'dapiPublicGetTime'
          response = getattr(self, method)(query)
          return self.safe_integer(response, 'serverTime')
  
      def load_time_difference(self, params={}):
          serverTime = self.fetch_time(params)
          after = self.milliseconds()
          self.options['timeDifference'] = after - serverTime
          return self.options['timeDifference']
  
      def fetch_currencies(self, params={}):
          fetchCurrenciesEnabled = self.safe_value(self.options, 'fetchCurrencies')
          if not fetchCurrenciesEnabled:
              return None
          # self endpoint requires authentication
          # while fetchCurrencies is a public API method by design
          # therefore we check the keys here
          # and fallback to generating the currencies from the markets
          if not self.check_required_credentials(False):
              return None
          # sandbox/testnet does not support sapi endpoints
          apiBackup = self.safe_string(self.urls, 'apiBackup')
          if apiBackup is not None:
              return None
          response = self.sapiGetCapitalConfigGetall(params)
          result = {}
          for i in range(0, len(response)):
              #
              #     {
              #         coin: 'LINK',
              #         depositAllEnable: True,
              #         withdrawAllEnable: True,
              #         name: 'ChainLink',
              #         free: '0.06168',
              #         locked: '0',
              #         freeze: '0',
              #         withdrawing: '0',
              #         ipoing: '0',
              #         ipoable: '0',
              #         storage: '0',
              #         isLegalMoney: False,
              #         trading: True,
              #         networkList: [
              #             {
              #                 network: 'BNB',
              #                 coin: 'LINK',
              #                 withdrawIntegerMultiple: '0',
              #                 isDefault: False,
              #                 depositEnable: True,
              #                 withdrawEnable: True,
              #                 depositDesc: '',
              #                 withdrawDesc: '',
              #                 specialTips: 'Both a MEMO and an Address are required to successfully deposit your LINK BEP2 tokens to Binance.',
              #                 name: 'BEP2',
              #                 resetAddressStatus: False,
              #                 addressRegex: '^(bnb1)[0-9a-z]{38}$',
              #                 memoRegex: '^[0-9A-Za-z\\-_]{1,120}$',
              #                 withdrawFee: '0.002',
              #                 withdrawMin: '0.01',
              #                 withdrawMax: '9999999',
              #                 minConfirm: 1,
              #                 unLockConfirm: 0
              #             },
              #             {
              #                 network: 'BSC',
              #                 coin: 'LINK',
              #                 withdrawIntegerMultiple: '0.00000001',
              #                 isDefault: False,
              #                 depositEnable: True,
              #                 withdrawEnable: True,
              #                 depositDesc: '',
              #                 withdrawDesc: '',
              #                 specialTips: '',
              #                 name: 'BEP20(BSC)',
              #                 resetAddressStatus: False,
              #                 addressRegex: '^(0x)[0-9A-Fa-f]{40}$',
              #                 memoRegex: '',
              #                 withdrawFee: '0.005',
              #                 withdrawMin: '0.01',
              #                 withdrawMax: '9999999',
              #                 minConfirm: 15,
              #                 unLockConfirm: 0
              #             },
              #             {
              #                 network: 'ETH',
              #                 coin: 'LINK',
              #                 withdrawIntegerMultiple: '0.00000001',
              #                 isDefault: True,
              #                 depositEnable: True,
              #                 withdrawEnable: True,
              #                 depositDesc: '',
              #                 withdrawDesc: '',
              #                 name: 'ERC20',
              #                 resetAddressStatus: False,
              #                 addressRegex: '^(0x)[0-9A-Fa-f]{40}$',
              #                 memoRegex: '',
              #                 withdrawFee: '0.34',
              #                 withdrawMin: '0.68',
              #                 withdrawMax: '0',
              #                 minConfirm: 12,
              #                 unLockConfirm: 0
              #             }
              #         ]
              #     }
              #
              entry = response[i]
              id = self.safe_string(entry, 'coin')
              name = self.safe_string(entry, 'name')
              code = self.safe_currency_code(id)
              precision = None
              isWithdrawEnabled = True
              isDepositEnabled = True
              networkList = self.safe_value(entry, 'networkList', [])
              fees = {}
              fee = None
              for j in range(0, len(networkList)):
                  networkItem = networkList[j]
                  network = self.safe_string(networkItem, 'network')
                  # name = self.safe_string(networkItem, 'name')
                  withdrawFee = self.safe_number(networkItem, 'withdrawFee')
                  depositEnable = self.safe_value(networkItem, 'depositEnable')
                  withdrawEnable = self.safe_value(networkItem, 'withdrawEnable')
                  isDepositEnabled = isDepositEnabled or depositEnable
                  isWithdrawEnabled = isWithdrawEnabled or withdrawEnable
                  fees[network] = withdrawFee
                  isDefault = self.safe_value(networkItem, 'isDefault')
                  if isDefault or fee is None:
                      fee = withdrawFee
              trading = self.safe_value(entry, 'trading')
              active = (isWithdrawEnabled and isDepositEnabled and trading)
              result[code] = {
                  'id': id,
                  'name': name,
                  'code': code,
                  'precision': precision,
                  'info': entry,
                  'active': active,
                  'networks': networkList,
                  'fee': fee,
                  'fees': fees,
                  'limits': self.limits,
              }
          return result
  
      def fetch_markets(self, params={}):
          defaultType = self.safe_string_2(self.options, 'fetchMarkets', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          query = self.omit(params, 'type')
          if (type != 'spot') and (type != 'future') and (type != 'margin') and (type != 'delivery'):
              raise ExchangeError(self.id + " does not support '" + type + "' type, set exchange.options['defaultType'] to 'spot', 'margin', 'delivery' or 'future'")  # eslint-disable-line quotes
          method = 'publicGetExchangeInfo'
          if type == 'future':
              method = 'fapiPublicGetExchangeInfo'
          elif type == 'delivery':
              method = 'dapiPublicGetExchangeInfo'
          response = getattr(self, method)(query)
          #
          # spot / margin
          #
          #     {
          #         "timezone":"UTC",
          #         "serverTime":1575416692969,
          #         "rateLimits":[
          #             {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200},
          #             {"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":100},
          #             {"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":200000}
          #         ],
          #         "exchangeFilters":[],
          #         "symbols":[
          #             {
          #                 "symbol":"ETHBTC",
          #                 "status":"TRADING",
          #                 "baseAsset":"ETH",
          #                 "baseAssetPrecision":8,
          #                 "quoteAsset":"BTC",
          #                 "quotePrecision":8,
          #                 "baseCommissionPrecision":8,
          #                 "quoteCommissionPrecision":8,
          #                 "orderTypes":["LIMIT","LIMIT_MAKER","MARKET","STOP_LOSS_LIMIT","TAKE_PROFIT_LIMIT"],
          #                 "icebergAllowed":true,
          #                 "ocoAllowed":true,
          #                 "quoteOrderQtyMarketAllowed":true,
          #                 "isSpotTradingAllowed":true,
          #                 "isMarginTradingAllowed":true,
          #                 "filters":[
          #                     {"filterType":"PRICE_FILTER","minPrice":"0.00000100","maxPrice":"100000.00000000","tickSize":"0.00000100"},
          #                     {"filterType":"PERCENT_PRICE","multiplierUp":"5","multiplierDown":"0.2","avgPriceMins":5},
          #                     {"filterType":"LOT_SIZE","minQty":"0.00100000","maxQty":"100000.00000000","stepSize":"0.00100000"},
          #                     {"filterType":"MIN_NOTIONAL","minNotional":"0.00010000","applyToMarket":true,"avgPriceMins":5},
          #                     {"filterType":"ICEBERG_PARTS","limit":10},
          #                     {"filterType":"MARKET_LOT_SIZE","minQty":"0.00000000","maxQty":"63100.00000000","stepSize":"0.00000000"},
          #                     {"filterType":"MAX_NUM_ALGO_ORDERS","maxNumAlgoOrders":5}
          #                 ]
          #             },
          #         ],
          #     }
          #
          # futures/usdt-margined(fapi)
          #
          #     {
          #         "timezone":"UTC",
          #         "serverTime":1575417244353,
          #         "rateLimits":[
          #             {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200},
          #             {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":1200}
          #         ],
          #         "exchangeFilters":[],
          #         "symbols":[
          #             {
          #                 "symbol":"BTCUSDT",
          #                 "status":"TRADING",
          #                 "maintMarginPercent":"2.5000",
          #                 "requiredMarginPercent":"5.0000",
          #                 "baseAsset":"BTC",
          #                 "quoteAsset":"USDT",
          #                 "pricePrecision":2,
          #                 "quantityPrecision":3,
          #                 "baseAssetPrecision":8,
          #                 "quotePrecision":8,
          #                 "filters":[
          #                     {"minPrice":"0.01","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.01"},
          #                     {"stepSize":"0.001","filterType":"LOT_SIZE","maxQty":"1000","minQty":"0.001"},
          #                     {"stepSize":"0.001","filterType":"MARKET_LOT_SIZE","maxQty":"1000","minQty":"0.001"},
          #                     {"limit":200,"filterType":"MAX_NUM_ORDERS"},
          #                     {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"}
          #                 ],
          #                 "orderTypes":["LIMIT","MARKET","STOP"],
          #                 "timeInForce":["GTC","IOC","FOK","GTX"]
          #             }
          #         ]
          #     }
          #
          # delivery/coin-margined(dapi)
          #
          #     {
          #         "timezone": "UTC",
          #         "serverTime": 1597667052958,
          #         "rateLimits": [
          #             {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000},
          #             {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":6000}
          #         ],
          #         "exchangeFilters": [],
          #         "symbols": [
          #             {
          #                 "symbol": "BTCUSD_200925",
          #                 "pair": "BTCUSD",
          #                 "contractType": "CURRENT_QUARTER",
          #                 "deliveryDate": 1601020800000,
          #                 "onboardDate": 1590739200000,
          #                 "contractStatus": "TRADING",
          #                 "contractSize": 100,
          #                 "marginAsset": "BTC",
          #                 "maintMarginPercent": "2.5000",
          #                 "requiredMarginPercent": "5.0000",
          #                 "baseAsset": "BTC",
          #                 "quoteAsset": "USD",
          #                 "pricePrecision": 1,
          #                 "quantityPrecision": 0,
          #                 "baseAssetPrecision": 8,
          #                 "quotePrecision": 8,
          #                 "equalQtyPrecision": 4,
          #                 "filters": [
          #                     {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"},
          #                     {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"},
          #                     {"stepSize":"0","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"},
          #                     {"limit":200,"filterType":"MAX_NUM_ORDERS"},
          #                     {"multiplierDown":"0.9500","multiplierUp":"1.0500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"}
          #                 ],
          #                 "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"],
          #                 "timeInForce": ["GTC","IOC","FOK","GTX"]
          #             },
          #             {
          #                 "symbol": "BTCUSD_PERP",
          #                 "pair": "BTCUSD",
          #                 "contractType": "PERPETUAL",
          #                 "deliveryDate": 4133404800000,
          #                 "onboardDate": 1596006000000,
          #                 "contractStatus": "TRADING",
          #                 "contractSize": 100,
          #                 "marginAsset": "BTC",
          #                 "maintMarginPercent": "2.5000",
          #                 "requiredMarginPercent": "5.0000",
          #                 "baseAsset": "BTC",
          #                 "quoteAsset": "USD",
          #                 "pricePrecision": 1,
          #                 "quantityPrecision": 0,
          #                 "baseAssetPrecision": 8,
          #                 "quotePrecision": 8,
          #                 "equalQtyPrecision": 4,
          #                 "filters": [
          #                     {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"},
          #                     {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"},
          #                     {"stepSize":"1","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"},
          #                     {"limit":200,"filterType":"MAX_NUM_ORDERS"},
          #                     {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"}
          #                 ],
          #                 "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"],
          #                 "timeInForce": ["GTC","IOC","FOK","GTX"]
          #             }
          #         ]
          #     }
          #
          if self.options['adjustForTimeDifference']:
              self.load_time_difference()
          markets = self.safe_value(response, 'symbols', [])
          result = []
          for i in range(0, len(markets)):
              market = markets[i]
              spot = (type == 'spot')
              future = (type == 'future')
              delivery = (type == 'delivery')
              id = self.safe_string(market, 'symbol')
              lowercaseId = self.safe_string_lower(market, 'symbol')
              baseId = self.safe_string(market, 'baseAsset')
              quoteId = self.safe_string(market, 'quoteAsset')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              contractType = self.safe_string(market, 'contractType')
              idSymbol = (future or delivery) and (contractType != 'PERPETUAL')
              symbol = None
              expiry = None
              if idSymbol:
                  symbol = id
                  expiry = self.safe_integer(market, 'deliveryDate')
              else:
                  symbol = base + '/' + quote
              filters = self.safe_value(market, 'filters', [])
              filtersByType = self.index_by(filters, 'filterType')
              precision = {
                  'base': self.safe_integer(market, 'baseAssetPrecision'),
                  'quote': self.safe_integer(market, 'quotePrecision'),
                  'amount': self.safe_integer(market, 'quantityPrecision'),
                  'price': self.safe_integer(market, 'pricePrecision'),
              }
              status = self.safe_string_2(market, 'status', 'contractStatus')
              active = (status == 'TRADING')
              margin = self.safe_value(market, 'isMarginTradingAllowed', False)
              contractSize = None
              fees = self.fees
              if future or delivery:
                  contractSize = self.safe_string(market, 'contractSize', '1')
                  fees = self.fees[type]
              maker = fees['trading']['maker']
              taker = fees['trading']['taker']
              settleId = self.safe_string(market, 'marginAsset')
              settle = self.safe_currency_code(settleId)
              entry = {
                  'id': id,
                  'lowercaseId': lowercaseId,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'info': market,
                  'spot': spot,
                  'type': type,
                  'margin': margin,
                  'future': future,
                  'delivery': delivery,
                  'linear': future,
                  'inverse': delivery,
                  'expiry': expiry,
                  'expiryDatetime': self.iso8601(expiry),
                  'settleId': settleId,
                  'settle': settle,
                  'active': active,
                  'precision': precision,
                  'contractSize': contractSize,
                  'maker': maker,
                  'taker': taker,
                  'limits': {
                      'amount': {
                          'min': None,
                          'max': None,
                      },
                      'price': {
                          'min': None,
                          'max': None,
                      },
                      'cost': {
                          'min': None,
                          'max': None,
                      },
                  },
              }
              if 'PRICE_FILTER' in filtersByType:
                  filter = self.safe_value(filtersByType, 'PRICE_FILTER', {})
                  tickSize = self.safe_string(filter, 'tickSize')
                  entry['precision']['price'] = self.precision_from_string(tickSize)
                  # PRICE_FILTER reports zero values for maxPrice
                  # since they updated filter types in November 2018
                  # https://github.com/ccxt/ccxt/issues/4286
                  # therefore limits['price']['max'] doesn't have any meaningful value except None
                  entry['limits']['price'] = {
                      'min': self.safe_number(filter, 'minPrice'),
                      'max': self.safe_number(filter, 'maxPrice'),
                  }
                  entry['precision']['price'] = self.precision_from_string(filter['tickSize'])
              if 'LOT_SIZE' in filtersByType:
                  filter = self.safe_value(filtersByType, 'LOT_SIZE', {})
                  stepSize = self.safe_string(filter, 'stepSize')
                  entry['precision']['amount'] = self.precision_from_string(stepSize)
                  entry['limits']['amount'] = {
                      'min': self.safe_number(filter, 'minQty'),
                      'max': self.safe_number(filter, 'maxQty'),
                  }
              if 'MARKET_LOT_SIZE' in filtersByType:
                  filter = self.safe_value(filtersByType, 'MARKET_LOT_SIZE', {})
                  entry['limits']['market'] = {
                      'min': self.safe_number(filter, 'minQty'),
                      'max': self.safe_number(filter, 'maxQty'),
                  }
              if 'MIN_NOTIONAL' in filtersByType:
                  filter = self.safe_value(filtersByType, 'MIN_NOTIONAL', {})
                  entry['limits']['cost']['min'] = self.safe_number_2(filter, 'minNotional', 'notional')
              result.append(entry)
          return result
  
      def fetch_balance(self, params={}):
          self.load_markets()
          defaultType = self.safe_string_2(self.options, 'fetchBalance', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          method = 'privateGetAccount'
          if type == 'future':
              options = self.safe_value(self.options, type, {})
              fetchBalanceOptions = self.safe_value(options, 'fetchBalance', {})
              method = self.safe_string(fetchBalanceOptions, 'method', 'fapiPrivateV2GetAccount')
          elif type == 'delivery':
              options = self.safe_value(self.options, type, {})
              fetchBalanceOptions = self.safe_value(options, 'fetchBalance', {})
              method = self.safe_string(fetchBalanceOptions, 'method', 'dapiPrivateGetAccount')
          elif type == 'margin':
              method = 'sapiGetMarginAccount'
          elif type == 'savings':
              method = 'sapiGetLendingUnionAccount'
          elif type == 'funding':
              method = 'sapiPostAssetGetFundingAsset'
          query = self.omit(params, 'type')
          response = getattr(self, method)(query)
          #
          # spot
          #
          #     {
          #         makerCommission: 10,
          #         takerCommission: 10,
          #         buyerCommission: 0,
          #         sellerCommission: 0,
          #         canTrade: True,
          #         canWithdraw: True,
          #         canDeposit: True,
          #         updateTime: 1575357359602,
          #         accountType: "MARGIN",
          #         balances: [
          #             {asset: "BTC", free: "0.00219821", locked: "0.00000000"  },
          #         ]
          #     }
          #
          # margin
          #
          #     {
          #         "borrowEnabled":true,
          #         "marginLevel":"999.00000000",
          #         "totalAssetOfBtc":"0.00000000",
          #         "totalLiabilityOfBtc":"0.00000000",
          #         "totalNetAssetOfBtc":"0.00000000",
          #         "tradeEnabled":true,
          #         "transferEnabled":true,
          #         "userAssets":[
          #             {"asset":"MATIC","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"},
          #             {"asset":"VET","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"},
          #             {"asset":"USDT","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"}
          #         ],
          #     }
          #
          # futures(fapi)
          #
          #     fapiPrivateGetAccount
          #
          #     {
          #         "feeTier":0,
          #         "canTrade":true,
          #         "canDeposit":true,
          #         "canWithdraw":true,
          #         "updateTime":0,
          #         "totalInitialMargin":"0.00000000",
          #         "totalMaintMargin":"0.00000000",
          #         "totalWalletBalance":"4.54000000",
          #         "totalUnrealizedProfit":"0.00000000",
          #         "totalMarginBalance":"4.54000000",
          #         "totalPositionInitialMargin":"0.00000000",
          #         "totalOpenOrderInitialMargin":"0.00000000",
          #         "maxWithdrawAmount":"4.54000000",
          #         "assets":[
          #             {
          #                 "asset":"USDT",
          #                 "walletBalance":"4.54000000",
          #                 "unrealizedProfit":"0.00000000",
          #                 "marginBalance":"4.54000000",
          #                 "maintMargin":"0.00000000",
          #                 "initialMargin":"0.00000000",
          #                 "positionInitialMargin":"0.00000000",
          #                 "openOrderInitialMargin":"0.00000000",
          #                 "maxWithdrawAmount":"4.54000000"
          #             }
          #         ],
          #         "positions":[
          #             {
          #                 "symbol":"BTCUSDT",
          #                 "initialMargin":"0.00000",
          #                 "maintMargin":"0.00000",
          #                 "unrealizedProfit":"0.00000000",
          #                 "positionInitialMargin":"0.00000",
          #                 "openOrderInitialMargin":"0.00000"
          #             }
          #         ]
          #     }
          #
          #     fapiPrivateV2GetAccount
          #
          #     {
          #         "feeTier":0,
          #         "canTrade":true,
          #         "canDeposit":true,
          #         "canWithdraw":true,
          #         "updateTime":0,
          #         "totalInitialMargin":"0.00000000",
          #         "totalMaintMargin":"0.00000000",
          #         "totalWalletBalance":"0.00000000",
          #         "totalUnrealizedProfit":"0.00000000",
          #         "totalMarginBalance":"0.00000000",
          #         "totalPositionInitialMargin":"0.00000000",
          #         "totalOpenOrderInitialMargin":"0.00000000",
          #         "totalCrossWalletBalance":"0.00000000",
          #         "totalCrossUnPnl":"0.00000000",
          #         "availableBalance":"0.00000000",
          #         "maxWithdrawAmount":"0.00000000",
          #         "assets":[
          #             {
          #                 "asset":"BNB",
          #                 "walletBalance":"0.01000000",
          #                 "unrealizedProfit":"0.00000000",
          #                 "marginBalance":"0.01000000",
          #                 "maintMargin":"0.00000000",
          #                 "initialMargin":"0.00000000",
          #                 "positionInitialMargin":"0.00000000",
          #                 "openOrderInitialMargin":"0.00000000",
          #                 "maxWithdrawAmount":"0.01000000",
          #                 "crossWalletBalance":"0.01000000",
          #                 "crossUnPnl":"0.00000000",
          #                 "availableBalance":"0.01000000"
          #             }
          #         ],
          #         "positions":[
          #             {
          #                 "symbol":"BTCUSDT",
          #                 "initialMargin":"0",
          #                 "maintMargin":"0",
          #                 "unrealizedProfit":"0.00000000",
          #                 "positionInitialMargin":"0",
          #                 "openOrderInitialMargin":"0",
          #                 "leverage":"20",
          #                 "isolated":false,
          #                 "entryPrice":"0.00000",
          #                 "maxNotional":"5000000",
          #                 "positionSide":"BOTH"
          #             },
          #         ]
          #     }
          #
          #     fapiPrivateV2GetBalance
          #
          #     [
          #         {
          #             "accountAlias":"FzFzXquXXqoC",
          #             "asset":"BNB",
          #             "balance":"0.01000000",
          #             "crossWalletBalance":"0.01000000",
          #             "crossUnPnl":"0.00000000",
          #             "availableBalance":"0.01000000",
          #             "maxWithdrawAmount":"0.01000000"
          #         }
          #     ]
          #
          # savings
          #
          #     {
          #       "totalAmountInBTC": "0.3172",
          #       "totalAmountInUSDT": "10000",
          #       "totalFixedAmountInBTC": "0.3172",
          #       "totalFixedAmountInUSDT": "10000",
          #       "totalFlexibleInBTC": "0",
          #       "totalFlexibleInUSDT": "0",
          #       "positionAmountVos": [
          #         {
          #           "asset": "USDT",
          #           "amount": "10000",
          #           "amountInBTC": "0.3172",
          #           "amountInUSDT": "10000"
          #         },
          #         {
          #           "asset": "BUSD",
          #           "amount": "0",
          #           "amountInBTC": "0",
          #           "amountInUSDT": "0"
          #         }
          #       ]
          #     }
          #
          # binance pay
          #
          #     [
          #       {
          #         "asset": "BUSD",
          #         "free": "1129.83",
          #         "locked": "0",
          #         "freeze": "0",
          #         "withdrawing": "0"
          #       }
          #     ]
          #
          result = {
              'info': response,
          }
          timestamp = None
          if (type == 'spot') or (type == 'margin'):
              timestamp = self.safe_integer(response, 'updateTime')
              balances = self.safe_value_2(response, 'balances', 'userAssets', [])
              for i in range(0, len(balances)):
                  balance = balances[i]
                  currencyId = self.safe_string(balance, 'asset')
                  code = self.safe_currency_code(currencyId)
                  account = self.account()
                  account['free'] = self.safe_string(balance, 'free')
                  account['used'] = self.safe_string(balance, 'locked')
                  result[code] = account
          elif type == 'savings':
              positionAmountVos = self.safe_value(response, 'positionAmountVos')
              for i in range(0, len(positionAmountVos)):
                  entry = positionAmountVos[i]
                  currencyId = self.safe_string(entry, 'asset')
                  code = self.safe_currency_code(currencyId)
                  account = self.account()
                  usedAndTotal = self.safe_string(entry, 'amount')
                  account['total'] = usedAndTotal
                  account['used'] = usedAndTotal
                  result[code] = account
          elif type == 'funding':
              for i in range(0, len(response)):
                  entry = response[i]
                  account = self.account()
                  currencyId = self.safe_string(entry, 'asset')
                  code = self.safe_currency_code(currencyId)
                  account['free'] = self.safe_string(entry, 'free')
                  frozen = self.safe_string(entry, 'freeze')
                  withdrawing = self.safe_string(entry, 'withdrawing')
                  locked = self.safe_string(entry, 'locked')
                  account['used'] = Precise.string_add(frozen, Precise.string_add(locked, withdrawing))
                  result[code] = account
          else:
              balances = response
              if not isinstance(response, list):
                  balances = self.safe_value(response, 'assets', [])
              for i in range(0, len(balances)):
                  balance = balances[i]
                  currencyId = self.safe_string(balance, 'asset')
                  code = self.safe_currency_code(currencyId)
                  account = self.account()
                  account['free'] = self.safe_string(balance, 'availableBalance')
                  account['used'] = self.safe_string(balance, 'initialMargin')
                  account['total'] = self.safe_string_2(balance, 'marginBalance', 'balance')
                  result[code] = account
          result['timestamp'] = timestamp
          result['datetime'] = self.iso8601(timestamp)
          return self.parse_balance(result)
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          if limit is not None:
              request['limit'] = limit  # default 100, max 5000, see https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#order-book
          method = 'publicGetDepth'
          if market['linear']:
              method = 'fapiPublicGetDepth'
          elif market['inverse']:
              method = 'dapiPublicGetDepth'
          response = getattr(self, method)(self.extend(request, params))
          #
          # future
          #
          #     {
          #         "lastUpdateId":333598053905,
          #         "E":1618631511986,
          #         "T":1618631511964,
          #         "bids":[
          #             ["2493.56","20.189"],
          #             ["2493.54","1.000"],
          #             ["2493.51","0.005"],["2493.37","0.280"],["2493.31","0.865"],["2493.30","0.514"],["2493.29","2.309"],["2493.25","1.500"],["2493.23","0.012"],["2493.22","7.240"],["2493.21","3.349"],["2493.20","2.030"],["2493.19","58.118"],["2493.18","174.836"],["2493.17","14.436"],["2493.12","2.000"],["2493.09","3.232"],["2493.08","2.010"],["2493.07","2.000"],["2493.06","2.000"],["2493.05","2.684"],["2493.04","2.000"],["2493.03","2.000"],["2493.02","5.000"],["2493.01","2.000"],["2493.00","1.035"],["2492.99","8.546"],["2492.98","4.012"],["2492.96","40.937"],["2492.95","40.595"],["2492.94","21.051"],["2492.92","4.012"],["2492.91","0.200"],["2492.85","2.000"],["2492.83","24.929"],["2492.81","50.000"],["2492.80","0.030"],["2492.76","0.264"],["2492.73","32.098"],["2492.71","32.664"],["2492.70","4.228"],["2492.65","1.230"],["2492.61","5.598"],["2492.60","34.786"],["2492.58","10.393"],["2492.54","4.543"],["2492.50","0.400"],["2492.49","0.600"],["2492.48","4.941"],["2492.45","1.207"],["2492.43","4.878"],["2492.40","4.762"],["2492.39","36.489"],["2492.37","3.000"],["2492.36","4.882"],["2492.33","28.117"],["2492.29","0.490"],["2492.28","76.365"],["2492.27","0.200"],["2492.23","3.804"],["2492.22","1.000"],["2492.19","20.011"],["2492.17","13.500"],["2492.16","4.058"],["2492.14","35.673"],["2492.13","1.915"],["2492.12","76.896"],["2492.10","8.050"],["2492.01","16.615"],["2492.00","10.335"],["2491.95","5.880"],["2491.93","10.000"],["2491.92","3.916"],["2491.90","0.795"],["2491.87","22.000"],["2491.85","1.260"],["2491.84","4.014"],["2491.83","6.668"],["2491.73","0.855"],["2491.72","7.572"],["2491.71","7.000"],["2491.68","3.916"],["2491.66","2.500"],["2491.64","4.945"],["2491.63","2.302"],["2491.62","4.012"],["2491.61","16.170"],["2491.60","0.793"],["2491.59","0.403"],["2491.57","17.445"],["2491.56","88.177"],["2491.53","10.000"],["2491.47","0.013"],["2491.45","0.157"],["2491.44","11.733"],["2491.39","3.593"],["2491.38","3.570"],["2491.36","28.077"],["2491.35","0.808"],["2491.30","0.065"],["2491.29","4.880"],["2491.27","22.000"],["2491.24","9.021"],["2491.23","68.393"],["2491.22","0.050"],["2491.21","1.316"],["2491.20","4.000"],["2491.19","0.108"],["2491.18","0.498"],["2491.17","5.000"],["2491.14","10.000"],["2491.13","0.383"],["2491.12","125.959"],["2491.10","0.870"],["2491.08","10.518"],["2491.05","54.743"],["2491.01","7.980"],["2490.96","3.916"],["2490.95","0.135"],["2490.91","0.140"],["2490.89","8.424"],["2490.88","5.930"],["2490.84","1.208"],["2490.83","2.005"],["2490.82","5.517"],["2490.81","73.707"],["2490.80","1.042"],["2490.79","9.626"],["2490.72","3.916"],["2490.70","0.148"],["2490.69","0.403"],["2490.68","0.012"],["2490.67","21.887"],["2490.66","0.008"],["2490.64","11.500"],["2490.61","0.005"],["2490.58","68.175"],["2490.55","0.218"],["2490.54","14.132"],["2490.53","5.157"],["2490.50","0.018"],["2490.49","9.216"],["2490.48","3.979"],["2490.47","1.884"],["2490.44","0.003"],["2490.36","14.132"],["2490.35","2.008"],["2490.34","0.200"],["2490.33","0.015"],["2490.30","0.065"],["2490.29","5.500"],["2490.28","24.203"],["2490.26","4.373"],["2490.25","0.026"],["2490.24","4.000"],["2490.23","177.628"],["2490.22","14.132"],["2490.21","0.181"],["2490.20","0.645"],["2490.19","9.024"],["2490.18","0.108"],["2490.17","0.085"],["2490.16","0.077"],["2490.14","0.275"],["2490.10","0.080"],["2490.07","0.015"],["2490.04","6.056"],["2490.00","6.796"],["2489.98","0.005"],["2489.97","0.258"],["2489.96","10.084"],["2489.95","1.202"],["2489.91","10.121"],["2489.90","10.084"],["2489.88","0.040"],["2489.87","0.004"],["2489.85","0.003"],["2489.76","3.916"],["2489.73","10.084"],["2489.71","0.272"],["2489.70","12.834"],["2489.67","0.403"],["2489.66","0.362"],["2489.64","0.738"],["2489.63","193.236"],["2489.62","14.152"],["2489.61","0.157"],["2489.59","4.011"],["2489.57","0.015"],["2489.55","0.046"],["2489.52","3.921"],["2489.51","0.005"],["2489.45","80.000"],["2489.44","0.649"],["2489.43","10.088"],["2489.39","0.009"],["2489.37","14.132"],["2489.35","72.262"],["2489.34","10.084"],["2489.33","14.136"],["2489.32","23.953"],["2489.30","0.065"],["2489.28","8.136"],["2489.24","8.022"],["2489.19","14.132"],["2489.18","0.085"],["2489.17","0.108"],["2489.14","10.084"],["2489.13","3.142"],["2489.12","77.827"],["2489.11","10.084"],["2489.10","0.080"],["2489.09","50.024"],["2489.04","3.916"],["2489.03","0.008"],["2489.01","10.084"],["2488.99","0.135"],["2488.98","0.187"],["2488.96","0.324"],["2488.92","0.064"],["2488.85","16.056"],["2488.83","14.132"],["2488.80","3.916"],["2488.79","10.084"],["2488.77","4.414"],["2488.76","0.005"],["2488.75","13.685"],["2488.73","0.020"],["2488.69","0.157"],["2488.60","80.000"],["2488.58","10.164"],["2488.57","0.004"],["2488.56","3.933"],["2488.54","3.311"],["2488.51","12.814"],["2488.50","80.099"],["2488.48","0.684"],["2488.44","0.024"],["2488.42","68.180"],["2488.39","4.412"],["2488.38","26.138"],["2488.34","44.134"],["2488.32","8.014"],["2488.30","0.065"],["2488.29","0.009"],["2488.27","4.513"],["2488.26","4.222"],["2488.25","80.000"],["2488.23","0.007"],["2488.22","0.281"],["2488.19","0.100"],["2488.18","80.100"],["2488.17","80.000"],["2488.16","8.197"],["2488.15","79.184"],["2488.13","0.025"],["2488.11","0.050"],["2488.10","0.080"],["2488.08","3.919"],["2488.04","40.103"],["2488.03","0.120"],["2488.02","0.008"],["2488.01","0.140"],["2488.00","0.406"],["2487.99","0.384"],["2487.98","0.060"],["2487.96","8.010"],["2487.94","0.246"],["2487.93","0.020"],["2487.91","0.136"],["2487.87","0.403"],["2487.84","17.910"],["2487.81","0.005"],["2487.80","0.073"],["2487.74","36.000"],["2487.73","3.225"],["2487.72","0.018"],["2487.71","0.319"],["2487.70","0.006"],["2487.66","0.003"],["2487.64","0.003"],["2487.63","0.008"],["2487.62","0.040"],["2487.60","3.916"],["2487.54","0.805"],["2487.52","0.022"],["2487.51","0.003"],["2487.50","0.051"],["2487.49","6.081"],["2487.47","80.015"],["2487.46","4.735"],["2487.45","30.000"],["2487.41","0.096"],["2487.40","0.078"],["2487.39","0.103"],["2487.37","2.279"],["2487.36","8.152"],["2487.35","2.145"],["2487.32","12.816"],["2487.31","10.023"],["2487.30","0.157"],["2487.27","0.005"],["2487.26","4.010"],["2487.25","0.008"],["2487.24","0.003"],["2487.23","0.014"],["2487.20","0.085"],["2487.17","0.011"],["2487.14","3.217"],["2487.12","3.916"],["2487.11","0.300"],["2487.10","0.088"],["2487.08","10.097"],["2487.07","1.467"],["2487.04","0.600"],["2487.01","18.363"],["2487.00","0.292"],["2486.99","0.014"],["2486.98","0.144"],["2486.97","0.443"],["2486.92","0.005"],["2486.91","0.016"],["2486.89","3.364"],["2486.88","4.166"],["2486.84","24.306"],["2486.83","0.181"],["2486.81","0.015"],["2486.80","0.082"],["2486.79","0.007"],["2486.76","0.011"],["2486.74","0.050"],["2486.73","0.782"],["2486.72","0.004"],["2486.69","0.003"],["2486.68","8.018"],["2486.66","10.004"],["2486.65","40.391"],["2486.64","3.916"],["2486.61","0.489"],["2486.60","0.196"],["2486.57","0.396"],["2486.55","4.015"],["2486.51","3.000"],["2486.50","0.003"],["2486.48","0.005"],["2486.47","0.010"],["2486.45","4.011"],["2486.44","0.602"],["2486.43","0.566"],["2486.42","3.140"],["2486.40","3.958"],["2486.39","0.003"],["2486.34","0.010"],["2486.31","6.281"],["2486.27","0.005"],["2486.26","0.004"],["2486.23","10.088"],["2486.22","0.015"],["2486.17","0.030"],["2486.16","3.916"],["2486.15","0.020"],["2486.13","13.130"],["2486.12","82.414"],["2486.11","0.244"],["2486.10","0.132"],["2486.08","0.720"],["2486.06","0.385"],["2486.01","0.004"],["2486.00","2.359"],["2485.99","154.159"],["2485.98","20.054"],["2485.96","1.000"],["2485.95","0.190"],["2485.92","4.463"],["2485.90","1.557"],["2485.87","0.402"],["2485.85","0.114"],["2485.81","0.900"],["2485.76","4.700"],["2485.75","0.300"],["2485.74","0.196"],["2485.73","4.010"],["2485.72","0.323"],["2485.70","0.263"],["2485.69","0.261"],["2485.68","3.688"],["2485.67","0.005"],["2485.64","1.216"],["2485.63","0.005"],["2485.62","0.015"],["2485.61","0.033"],["2485.60","0.004"],["2485.58","2.012"],["2485.56","0.020"],["2485.54","0.699"],["2485.52","0.003"],["2485.51","1.830"],["2485.48","5.964"],["2485.47","0.015"],["2485.44","7.251"],["2485.43","0.006"],["2485.42","0.644"],["2485.40","8.026"],["2485.38","0.489"],["2485.36","0.014"],["2485.35","0.005"],["2485.31","1.507"],["2485.30","2.107"],["2485.29","0.039"],["2485.28","0.642"],["2485.26","1.990"],["2485.25","4.996"],["2485.23","0.003"],["2485.22","0.277"],["2485.21","0.121"],["2485.20","3.952"],["2485.18","0.006"],["2485.17","0.043"],["2485.15","4.008"],["2485.14","4.434"],["2485.13","1.003"],["2485.05","0.204"],["2485.04","0.254"],["2485.02","5.000"],["2485.01","0.050"],["2485.00","80.821"],["2484.96","3.941"],["2484.95","10.023"],["2484.94","13.935"],["2484.92","0.059"],["2484.90","150.000"],["2484.89","0.004"],["2484.88","150.127"],["2484.87","0.004"],["2484.85","0.100"],["2484.83","0.006"],["2484.82","0.030"],["2484.81","1.246"],["2484.80","0.003"],["2484.79","0.045"],["2484.77","0.003"],["2484.74","0.036"],["2484.72","3.919"],["2484.70","0.134"],["2484.68","1.111"],["2484.66","76.955"],["2484.60","2.580"],["2484.59","31.432"],["2484.58","1.468"],["2484.55","1.153"],["2484.54","0.265"],["2484.53","20.024"],["2484.51","1.047"],["2484.50","0.818"],["2484.49","0.022"],["2484.48","3.887"],["2484.46","0.048"],["2484.45","0.224"],["2484.44","0.174"],["2484.43","223.079"],["2484.42","0.014"],["2484.41","1.115"],["2484.39","26.090"],["2484.38","0.066"],["2484.37","0.121"],["2484.34","0.255"],["2484.33","23.968"],["2484.29","0.085"],["2484.27","1.128"],["2484.26","1.456"],["2484.24","3.916"],["2484.23","28.126"],["2484.22","1.329"],["2484.19","2.015"],["2484.18","0.263"],["2484.15","15.489"],["2484.14","1.135"],["2484.13","0.572"],["2484.12","8.032"],["2484.11","0.021"],["2484.09","0.059"],["2484.08","0.038"],["2484.07","0.147"],["2484.05","24.156"],["2484.04","0.008"],["2484.01","1.184"],["2484.00","4.641"],["2483.99","0.006"],["2483.97","0.294"],["2483.96","0.424"],["2483.94","3.660"],["2483.93","2.067"],["2483.92","0.008"],["2483.89","0.141"],["2483.88","1.089"],
          #             ["2483.87","110.000"],["2483.85","4.018"],["2483.81","150.077"],["2483.80","0.003"],["2483.77","0.020"]
          #         ],
          #         "asks":[
          #             ["2493.57","0.877"],
          #             ["2493.62","0.063"],
          #             ["2493.71","12.054"],
          #         ]
          #     }
          timestamp = self.safe_integer(response, 'T')
          orderbook = self.parse_order_book(response, symbol, timestamp)
          orderbook['nonce'] = self.safe_integer(response, 'lastUpdateId')
          return orderbook
  
      def parse_ticker(self, ticker, market=None):
          #
          #     {
          #         symbol: 'ETHBTC',
          #         priceChange: '0.00068700',
          #         priceChangePercent: '2.075',
          #         weightedAvgPrice: '0.03342681',
          #         prevClosePrice: '0.03310300',
          #         lastPrice: '0.03378900',
          #         lastQty: '0.07700000',
          #         bidPrice: '0.03378900',
          #         bidQty: '7.16800000',
          #         askPrice: '0.03379000',
          #         askQty: '24.00000000',
          #         openPrice: '0.03310200',
          #         highPrice: '0.03388900',
          #         lowPrice: '0.03306900',
          #         volume: '205478.41000000',
          #         quoteVolume: '6868.48826294',
          #         openTime: 1601469986932,
          #         closeTime: 1601556386932,
          #         firstId: 196098772,
          #         lastId: 196186315,
          #         count: 87544
          #     }
          #
          # coinm
          #     {
          #         baseVolume: '214549.95171161',
          #         closeTime: '1621965286847',
          #         count: '1283779',
          #         firstId: '152560106',
          #         highPrice: '39938.3',
          #         lastId: '153843955',
          #         lastPrice: '37993.4',
          #         lastQty: '1',
          #         lowPrice: '36457.2',
          #         openPrice: '37783.4',
          #         openTime: '1621878840000',
          #         pair: 'BTCUSD',
          #         priceChange: '210.0',
          #         priceChangePercent: '0.556',
          #         symbol: 'BTCUSD_PERP',
          #         volume: '81990451',
          #         weightedAvgPrice: '38215.08713747'
          #     }
          #
          timestamp = self.safe_integer(ticker, 'closeTime')
          marketId = self.safe_string(ticker, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          last = self.safe_number(ticker, 'lastPrice')
          isCoinm = ('baseVolume' in ticker)
          baseVolume = None
          quoteVolume = None
          if isCoinm:
              baseVolume = self.safe_number(ticker, 'baseVolume')
              quoteVolume = self.safe_number(ticker, 'volume')
          else:
              baseVolume = self.safe_number(ticker, 'volume')
              quoteVolume = self.safe_number(ticker, 'quoteVolume')
          return self.safe_ticker({
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_number(ticker, 'highPrice'),
              'low': self.safe_number(ticker, 'lowPrice'),
              'bid': self.safe_number(ticker, 'bidPrice'),
              'bidVolume': self.safe_number(ticker, 'bidQty'),
              'ask': self.safe_number(ticker, 'askPrice'),
              'askVolume': self.safe_number(ticker, 'askQty'),
              'vwap': self.safe_number(ticker, 'weightedAvgPrice'),
              'open': self.safe_number(ticker, 'openPrice'),
              'close': last,
              'last': last,
              'previousClose': self.safe_number(ticker, 'prevClosePrice'),  # previous day close
              'change': self.safe_number(ticker, 'priceChange'),
              'percentage': self.safe_number(ticker, 'priceChangePercent'),
              'average': None,
              'baseVolume': baseVolume,
              'quoteVolume': quoteVolume,
              'info': ticker,
          }, market)
  
      def fetch_status(self, params={}):
          response = self.sapiGetSystemStatus(params)
          status = self.safe_string(response, 'status')
          if status is not None:
              status = 'ok' if (status == '0') else 'maintenance'
              self.status = self.extend(self.status, {
                  'status': status,
                  'updated': self.milliseconds(),
              })
          return self.status
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          method = 'publicGetTicker24hr'
          if market['linear']:
              method = 'fapiPublicGetTicker24hr'
          elif market['inverse']:
              method = 'dapiPublicGetTicker24hr'
          response = getattr(self, method)(self.extend(request, params))
          if isinstance(response, list):
              firstTicker = self.safe_value(response, 0, {})
              return self.parse_ticker(firstTicker, market)
          return self.parse_ticker(response, market)
  
      def fetch_bids_asks(self, symbols=None, params={}):
          self.load_markets()
          defaultType = self.safe_string_2(self.options, 'fetchBidsAsks', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          query = self.omit(params, 'type')
          method = None
          if type == 'future':
              method = 'fapiPublicGetTickerBookTicker'
          elif type == 'delivery':
              method = 'dapiPublicGetTickerBookTicker'
          else:
              method = 'publicGetTickerBookTicker'
          response = getattr(self, method)(query)
          return self.parse_tickers(response, symbols)
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          defaultType = self.safe_string_2(self.options, 'fetchTickers', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          query = self.omit(params, 'type')
          defaultMethod = None
          if type == 'future':
              defaultMethod = 'fapiPublicGetTicker24hr'
          elif type == 'delivery':
              defaultMethod = 'dapiPublicGetTicker24hr'
          else:
              defaultMethod = 'publicGetTicker24hr'
          method = self.safe_string(self.options, 'fetchTickersMethod', defaultMethod)
          response = getattr(self, method)(query)
          return self.parse_tickers(response, symbols)
  
      def parse_ohlcv(self, ohlcv, market=None):
          # when api method = publicGetKlines or fapiPublicGetKlines or dapiPublicGetKlines
          #     [
          #         1591478520000,  # open time
          #         "0.02501300",  # open
          #         "0.02501800",  # high
          #         "0.02500000",  # low
          #         "0.02500000",  # close
          #         "22.19000000",  # volume
          #         1591478579999,  # close time
          #         "0.55490906",  # quote asset volume
          #         40,            # number of trades
          #         "10.92900000",  # taker buy base asset volume
          #         "0.27336462",  # taker buy quote asset volume
          #         "0"            # ignore
          #     ]
          #
          #  when api method = fapiPublicGetMarkPriceKlines or fapiPublicGetIndexPriceKlines
          #     [
          #         [
          #         1591256460000,          # Open time
          #         "9653.29201333",        # Open
          #         "9654.56401333",        # High
          #         "9653.07367333",        # Low
          #         "9653.07367333",        # Close(or latest price)
          #         "0",                    # Ignore
          #         1591256519999,          # Close time
          #         "0",                    # Ignore
          #         60,                     # Number of bisic data
          #         "0",                    # Ignore
          #         "0",                    # Ignore
          #         "0"                     # Ignore
          #         ]
          #     ]
          #
          return [
              self.safe_integer(ohlcv, 0),
              self.safe_number(ohlcv, 1),
              self.safe_number(ohlcv, 2),
              self.safe_number(ohlcv, 3),
              self.safe_number(ohlcv, 4),
              self.safe_number(ohlcv, 5),
          ]
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          # binance docs say that the default limit 500, max 1500 for futures, max 1000 for spot markets
          # the reality is that the time range wider than 500 candles won't work right
          defaultLimit = 500
          maxLimit = 1500
          price = self.safe_string(params, 'price')
          params = self.omit(params, 'price')
          limit = defaultLimit if (limit is None) else min(limit, maxLimit)
          request = {
              'interval': self.timeframes[timeframe],
              'limit': limit,
          }
          if price == 'index':
              request['pair'] = market['id']   # Index price takes self argument instead of symbol
          else:
              request['symbol'] = market['id']
          # duration = self.parse_timeframe(timeframe)
          if since is not None:
              request['startTime'] = since
              #
              # It didn't work before without the endTime
              # https://github.com/ccxt/ccxt/issues/8454
              #
              # if since > 0:
              #     endTime = self.sum(since, limit * duration * 1000 - 1)
              #     now = self.milliseconds()
              #     request['endTime'] = min(now, endTime)
              # }
          method = 'publicGetKlines'
          if price == 'mark':
              if market['inverse']:
                  method = 'dapiPublicGetMarkPriceKlines'
              else:
                  method = 'fapiPublicGetMarkPriceKlines'
          elif price == 'index':
              if market['inverse']:
                  method = 'dapiPublicGetIndexPriceKlines'
              else:
                  method = 'fapiPublicGetIndexPriceKlines'
          elif market['linear']:
              method = 'fapiPublicGetKlines'
          elif market['inverse']:
              method = 'dapiPublicGetKlines'
          response = getattr(self, method)(self.extend(request, params))
          #
          #     [
          #         [1591478520000,"0.02501300","0.02501800","0.02500000","0.02500000","22.19000000",1591478579999,"0.55490906",40,"10.92900000","0.27336462","0"],
          #         [1591478580000,"0.02499600","0.02500900","0.02499400","0.02500300","21.34700000",1591478639999,"0.53370468",24,"7.53800000","0.18850725","0"],
          #         [1591478640000,"0.02500800","0.02501100","0.02500300","0.02500800","154.14200000",1591478699999,"3.85405839",97,"5.32300000","0.13312641","0"],
          #     ]
          #
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      def fetch_mark_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          request = {
              'price': 'mark',
          }
          return self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params))
  
      def fetch_index_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          request = {
              'price': 'index',
          }
          return self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params))
  
      def parse_trade(self, trade, market=None):
          if 'isDustTrade' in trade:
              return self.parse_dust_trade(trade, market)
          #
          # aggregate trades
          # https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list
          #
          #     {
          #         "a": 26129,         # Aggregate tradeId
          #         "p": "0.01633102",  # Price
          #         "q": "4.70443515",  # Quantity
          #         "f": 27781,         # First tradeId
          #         "l": 27781,         # Last tradeId
          #         "T": 1498793709153,  # Timestamp
          #         "m": True,          # Was the buyer the maker?
          #         "M": True           # Was the trade the best price match?
          #     }
          #
          # recent public trades and old public trades
          # https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#recent-trades-list
          # https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#old-trade-lookup-market_data
          #
          #     {
          #         "id": 28457,
          #         "price": "4.00000100",
          #         "qty": "12.00000000",
          #         "time": 1499865549590,
          #         "isBuyerMaker": True,
          #         "isBestMatch": True
          #     }
          #
          # private trades
          # https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#account-trade-list-user_data
          #
          #     {
          #         "symbol": "BNBBTC",
          #         "id": 28457,
          #         "orderId": 100234,
          #         "price": "4.00000100",
          #         "qty": "12.00000000",
          #         "commission": "10.10000000",
          #         "commissionAsset": "BNB",
          #         "time": 1499865549590,
          #         "isBuyer": True,
          #         "isMaker": False,
          #         "isBestMatch": True
          #     }
          #
          # futures trades
          # https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data
          #
          #     {
          #       "accountId": 20,
          #       "buyer": False,
          #       "commission": "-0.07819010",
          #       "commissionAsset": "USDT",
          #       "counterPartyId": 653,
          #       "id": 698759,
          #       "maker": False,
          #       "orderId": 25851813,
          #       "price": "7819.01",
          #       "qty": "0.002",
          #       "quoteQty": "0.01563",
          #       "realizedPnl": "-0.91539999",
          #       "side": "SELL",
          #       "symbol": "BTCUSDT",
          #       "time": 1569514978020
          #     }
          #     {
          #       "symbol": "BTCUSDT",
          #       "id": 477128891,
          #       "orderId": 13809777875,
          #       "side": "SELL",
          #       "price": "38479.55",
          #       "qty": "0.001",
          #       "realizedPnl": "-0.00009534",
          #       "marginAsset": "USDT",
          #       "quoteQty": "38.47955",
          #       "commission": "-0.00076959",
          #       "commissionAsset": "USDT",
          #       "time": 1612733566708,
          #       "positionSide": "BOTH",
          #       "maker": True,
          #       "buyer": False
          #     }
          #
          # {respType: FULL}
          #
          #     {
          #       "price": "4000.00000000",
          #       "qty": "1.00000000",
          #       "commission": "4.00000000",
          #       "commissionAsset": "USDT",
          #       "tradeId": "1234",
          #     }
          #
          timestamp = self.safe_integer_2(trade, 'T', 'time')
          priceString = self.safe_string_2(trade, 'p', 'price')
          amountString = self.safe_string_2(trade, 'q', 'qty')
          price = self.parse_number(priceString)
          amount = self.parse_number(amountString)
          marketId = self.safe_string(trade, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          costString = Precise.string_mul(priceString, amountString)
          cost = self.parse_number(costString)
          id = self.safe_string_2(trade, 't', 'a')
          id = self.safe_string_2(trade, 'id', 'tradeId', id)
          side = None
          orderId = self.safe_string(trade, 'orderId')
          if 'm' in trade:
              side = 'sell' if trade['m'] else 'buy'  # self is reversed intentionally
          elif 'isBuyerMaker' in trade:
              side = 'sell' if trade['isBuyerMaker'] else 'buy'
          elif 'side' in trade:
              side = self.safe_string_lower(trade, 'side')
          else:
              if 'isBuyer' in trade:
                  side = 'buy' if trade['isBuyer'] else 'sell'  # self is a True side
          fee = None
          if 'commission' in trade:
              fee = {
                  'cost': self.safe_number(trade, 'commission'),
                  'currency': self.safe_currency_code(self.safe_string(trade, 'commissionAsset')),
              }
          takerOrMaker = None
          if 'isMaker' in trade:
              takerOrMaker = 'maker' if trade['isMaker'] else 'taker'
          if 'maker' in trade:
              takerOrMaker = 'maker' if trade['maker'] else 'taker'
          return {
              'info': trade,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'id': id,
              'order': orderId,
              'type': None,
              'side': side,
              'takerOrMaker': takerOrMaker,
              'price': price,
              'amount': amount,
              'cost': cost,
              'fee': fee,
          }
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
              # 'fromId': 123,    # ID to get aggregate trades from INCLUSIVE.
              # 'startTime': 456,  # Timestamp in ms to get aggregate trades from INCLUSIVE.
              # 'endTime': 789,   # Timestamp in ms to get aggregate trades until INCLUSIVE.
              # 'limit': 500,     # default = 500, maximum = 1000
          }
          defaultType = self.safe_string_2(self.options, 'fetchTrades', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          query = self.omit(params, 'type')
          defaultMethod = None
          if type == 'future':
              defaultMethod = 'fapiPublicGetAggTrades'
          elif type == 'delivery':
              defaultMethod = 'dapiPublicGetAggTrades'
          else:
              defaultMethod = 'publicGetAggTrades'
          method = self.safe_string(self.options, 'fetchTradesMethod', defaultMethod)
          if method == 'publicGetAggTrades':
              if since is not None:
                  request['startTime'] = since
                  # https://github.com/ccxt/ccxt/issues/6400
                  # https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list
                  request['endTime'] = self.sum(since, 3600000)
              if type == 'future':
                  method = 'fapiPublicGetAggTrades'
              elif type == 'delivery':
                  method = 'dapiPublicGetAggTrades'
          elif method == 'publicGetHistoricalTrades':
              if type == 'future':
                  method = 'fapiPublicGetHistoricalTrades'
              elif type == 'delivery':
                  method = 'dapiPublicGetHistoricalTrades'
          if limit is not None:
              request['limit'] = limit  # default = 500, maximum = 1000
          #
          # Caveats:
          # - default limit(500) applies only if no other parameters set, trades up
          #   to the maximum limit may be returned to satisfy other parameters
          # - if both limit and time window is set and time window contains more
          #   trades than the limit then the last trades from the window are returned
          # - 'tradeId' accepted and returned by self method is "aggregate" trade id
          #   which is different from actual trade id
          # - setting both fromId and time window results in error
          response = getattr(self, method)(self.extend(request, query))
          #
          # aggregate trades
          #
          #     [
          #         {
          #             "a": 26129,         # Aggregate tradeId
          #             "p": "0.01633102",  # Price
          #             "q": "4.70443515",  # Quantity
          #             "f": 27781,         # First tradeId
          #             "l": 27781,         # Last tradeId
          #             "T": 1498793709153,  # Timestamp
          #             "m": True,          # Was the buyer the maker?
          #             "M": True           # Was the trade the best price match?
          #         }
          #     ]
          #
          # recent public trades and historical public trades
          #
          #     [
          #         {
          #             "id": 28457,
          #             "price": "4.00000100",
          #             "qty": "12.00000000",
          #             "time": 1499865549590,
          #             "isBuyerMaker": True,
          #             "isBestMatch": True
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def parse_order_status(self, status):
          statuses = {
              'NEW': 'open',
              'PARTIALLY_FILLED': 'open',
              'FILLED': 'closed',
              'CANCELED': 'canceled',
              'PENDING_CANCEL': 'canceling',  # currently unused
              'REJECTED': 'rejected',
              'EXPIRED': 'expired',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_order(self, order, market=None):
          #
          # spot
          #
          #     {
          #         "symbol": "LTCBTC",
          #         "orderId": 1,
          #         "clientOrderId": "myOrder1",
          #         "price": "0.1",
          #         "origQty": "1.0",
          #         "executedQty": "0.0",
          #         "cummulativeQuoteQty": "0.0",
          #         "status": "NEW",
          #         "timeInForce": "GTC",
          #         "type": "LIMIT",
          #         "side": "BUY",
          #         "stopPrice": "0.0",
          #         "icebergQty": "0.0",
          #         "time": 1499827319559,
          #         "updateTime": 1499827319559,
          #         "isWorking": True
          #     }
          #
          # futures
          #
          #     {
          #         "symbol": "BTCUSDT",
          #         "orderId": 1,
          #         "clientOrderId": "myOrder1",
          #         "price": "0.1",
          #         "origQty": "1.0",
          #         "executedQty": "1.0",
          #         "cumQuote": "10.0",
          #         "status": "NEW",
          #         "timeInForce": "GTC",
          #         "type": "LIMIT",
          #         "side": "BUY",
          #         "stopPrice": "0.0",
          #         "updateTime": 1499827319559
          #     }
          #
          # createOrder with {"newOrderRespType": "FULL"}
          #
          #     {
          #       "symbol": "BTCUSDT",
          #       "orderId": 5403233939,
          #       "orderListId": -1,
          #       "clientOrderId": "x-R4BD3S825e669e75b6c14f69a2c43e",
          #       "transactTime": 1617151923742,
          #       "price": "0.00000000",
          #       "origQty": "0.00050000",
          #       "executedQty": "0.00050000",
          #       "cummulativeQuoteQty": "29.47081500",
          #       "status": "FILLED",
          #       "timeInForce": "GTC",
          #       "type": "MARKET",
          #       "side": "BUY",
          #       "fills": [
          #         {
          #           "price": "58941.63000000",
          #           "qty": "0.00050000",
          #           "commission": "0.00007050",
          #           "commissionAsset": "BNB",
          #           "tradeId": 737466631
          #         }
          #       ]
          #     }
          #
          # delivery
          #
          #     {
          #       "orderId": "18742727411",
          #       "symbol": "ETHUSD_PERP",
          #       "pair": "ETHUSD",
          #       "status": "FILLED",
          #       "clientOrderId": "x-xcKtGhcu3e2d1503fdd543b3b02419",
          #       "price": "0",
          #       "avgPrice": "4522.14",
          #       "origQty": "1",
          #       "executedQty": "1",
          #       "cumBase": "0.00221134",
          #       "timeInForce": "GTC",
          #       "type": "MARKET",
          #       "reduceOnly": False,
          #       "closePosition": False,
          #       "side": "SELL",
          #       "positionSide": "BOTH",
          #       "stopPrice": "0",
          #       "workingType": "CONTRACT_PRICE",
          #       "priceProtect": False,
          #       "origType": "MARKET",
          #       "time": "1636061952660",
          #       "updateTime": "1636061952660"
          #     }
          #
          status = self.parse_order_status(self.safe_string(order, 'status'))
          marketId = self.safe_string(order, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          filled = self.safe_string(order, 'executedQty', '0')
          timestamp = None
          lastTradeTimestamp = None
          if 'time' in order:
              timestamp = self.safe_integer(order, 'time')
          elif 'transactTime' in order:
              timestamp = self.safe_integer(order, 'transactTime')
          elif 'updateTime' in order:
              if status == 'open':
                  if Precise.string_gt(filled, '0'):
                      lastTradeTimestamp = self.safe_integer(order, 'updateTime')
                  else:
                      timestamp = self.safe_integer(order, 'updateTime')
          average = self.safe_string(order, 'avgPrice')
          price = self.safe_string(order, 'price')
          amount = self.safe_string(order, 'origQty')
          # - Spot/Margin market: cummulativeQuoteQty
          # - Futures market: cumQuote.
          #   Note self is not the actual cost, since Binance futures uses leverage to calculate margins.
          cost = self.safe_string_2(order, 'cummulativeQuoteQty', 'cumQuote')
          cost = self.safe_string_2(order, 'cumBase', cost)
          id = self.safe_string(order, 'orderId')
          type = self.safe_string_lower(order, 'type')
          side = self.safe_string_lower(order, 'side')
          fills = self.safe_value(order, 'fills', [])
          clientOrderId = self.safe_string(order, 'clientOrderId')
          timeInForce = self.safe_string(order, 'timeInForce')
          postOnly = (type == 'limit_maker') or (timeInForce == 'GTX')
          if type == 'limit_maker':
              type = 'limit'
          stopPriceString = self.safe_string(order, 'stopPrice')
          stopPrice = self.parse_number(self.omit_zero(stopPriceString))
          return self.safe_order2({
              'info': order,
              'id': id,
              'clientOrderId': clientOrderId,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': lastTradeTimestamp,
              'symbol': symbol,
              'type': type,
              'timeInForce': timeInForce,
              'postOnly': postOnly,
              'side': side,
              'price': price,
              'stopPrice': stopPrice,
              'amount': amount,
              'cost': cost,
              'average': average,
              'filled': filled,
              'remaining': None,
              'status': status,
              'fee': None,
              'trades': fills,
          }, market)
  
      def create_reduce_only_order(self, symbol, type, side, amount, price=None, params={}):
          request = {
              'reduceOnly': True,
          }
          return self.create_order(symbol, type, side, amount, price, self.extend(request, params))
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          defaultType = self.safe_string_2(self.options, 'createOrder', 'defaultType', 'spot')
          orderType = self.safe_string(params, 'type', defaultType)
          clientOrderId = self.safe_string_2(params, 'newClientOrderId', 'clientOrderId')
          params = self.omit(params, ['type', 'newClientOrderId', 'clientOrderId'])
          reduceOnly = self.safe_value(params, 'reduceOnly')
          if reduceOnly is not None:
              if (orderType != 'future') and (orderType != 'delivery'):
                  raise InvalidOrder(self.id + ' createOrder() does not support reduceOnly for ' + orderType + ' orders, reduceOnly orders are supported for futures and perpetuals only')
          method = 'privatePostOrder'
          if orderType == 'future':
              method = 'fapiPrivatePostOrder'
          elif orderType == 'delivery':
              method = 'dapiPrivatePostOrder'
          elif orderType == 'margin':
              method = 'sapiPostMarginOrder'
          # the next 5 lines are added to support for testing orders
          if market['spot']:
              test = self.safe_value(params, 'test', False)
              if test:
                  method += 'Test'
              params = self.omit(params, 'test')
          uppercaseType = type.upper()
          validOrderTypes = self.safe_value(market['info'], 'orderTypes')
          if not self.in_array(uppercaseType, validOrderTypes):
              raise InvalidOrder(self.id + ' ' + type + ' is not a valid order type in market ' + symbol)
          request = {
              'symbol': market['id'],
              'type': uppercaseType,
              'side': side.upper(),
          }
          if clientOrderId is None:
              broker = self.safe_value(self.options, 'broker')
              if broker is not None:
                  brokerId = self.safe_string(broker, orderType)
                  if brokerId is not None:
                      request['newClientOrderId'] = brokerId + self.uuid22()
          else:
              request['newClientOrderId'] = clientOrderId
          if (orderType == 'spot') or (orderType == 'margin'):
              request['newOrderRespType'] = self.safe_value(self.options['newOrderRespType'], type, 'RESULT')  # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
          else:
              # delivery and future
              request['newOrderRespType'] = 'RESULT'  # "ACK", "RESULT", default "ACK"
          # additional required fields depending on the order type
          timeInForceIsRequired = False
          priceIsRequired = False
          stopPriceIsRequired = False
          quantityIsRequired = False
          #
          # spot/margin
          #
          #     LIMIT                timeInForce, quantity, price
          #     MARKET               quantity or quoteOrderQty
          #     STOP_LOSS            quantity, stopPrice
          #     STOP_LOSS_LIMIT      timeInForce, quantity, price, stopPrice
          #     TAKE_PROFIT          quantity, stopPrice
          #     TAKE_PROFIT_LIMIT    timeInForce, quantity, price, stopPrice
          #     LIMIT_MAKER          quantity, price
          #
          # futures
          #
          #     LIMIT                timeInForce, quantity, price
          #     MARKET               quantity
          #     STOP/TAKE_PROFIT     quantity, price, stopPrice
          #     STOP_MARKET          stopPrice
          #     TAKE_PROFIT_MARKET   stopPrice
          #     TRAILING_STOP_MARKET callbackRate
          #
          if uppercaseType == 'MARKET':
              quoteOrderQty = self.safe_value(self.options, 'quoteOrderQty', False)
              if quoteOrderQty:
                  quoteOrderQty = self.safe_number(params, 'quoteOrderQty')
                  precision = market['precision']['price']
                  if quoteOrderQty is not None:
                      request['quoteOrderQty'] = self.decimal_to_precision(quoteOrderQty, TRUNCATE, precision, self.precisionMode)
                      params = self.omit(params, 'quoteOrderQty')
                  elif price is not None:
                      request['quoteOrderQty'] = self.decimal_to_precision(amount * price, TRUNCATE, precision, self.precisionMode)
                  else:
                      quantityIsRequired = True
              else:
                  quantityIsRequired = True
          elif uppercaseType == 'LIMIT':
              priceIsRequired = True
              timeInForceIsRequired = True
              quantityIsRequired = True
          elif (uppercaseType == 'STOP_LOSS') or (uppercaseType == 'TAKE_PROFIT'):
              stopPriceIsRequired = True
              quantityIsRequired = True
              if market['linear'] or market['inverse']:
                  priceIsRequired = True
          elif (uppercaseType == 'STOP_LOSS_LIMIT') or (uppercaseType == 'TAKE_PROFIT_LIMIT'):
              quantityIsRequired = True
              stopPriceIsRequired = True
              priceIsRequired = True
              timeInForceIsRequired = True
          elif uppercaseType == 'LIMIT_MAKER':
              priceIsRequired = True
              quantityIsRequired = True
          elif uppercaseType == 'STOP':
              quantityIsRequired = True
              stopPriceIsRequired = True
              priceIsRequired = True
          elif (uppercaseType == 'STOP_MARKET') or (uppercaseType == 'TAKE_PROFIT_MARKET'):
              closePosition = self.safe_value(params, 'closePosition')
              if closePosition is None:
                  quantityIsRequired = True
              stopPriceIsRequired = True
          elif uppercaseType == 'TRAILING_STOP_MARKET':
              quantityIsRequired = True
              callbackRate = self.safe_number(params, 'callbackRate')
              if callbackRate is None:
                  raise InvalidOrder(self.id + ' createOrder() requires a callbackRate extra param for a ' + type + ' order')
          if quantityIsRequired:
              request['quantity'] = self.amount_to_precision(symbol, amount)
          if priceIsRequired:
              if price is None:
                  raise InvalidOrder(self.id + ' createOrder() requires a price argument for a ' + type + ' order')
              request['price'] = self.price_to_precision(symbol, price)
          if timeInForceIsRequired:
              request['timeInForce'] = self.options['defaultTimeInForce']  # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel
          if stopPriceIsRequired:
              stopPrice = self.safe_number(params, 'stopPrice')
              if stopPrice is None:
                  raise InvalidOrder(self.id + ' createOrder() requires a stopPrice extra param for a ' + type + ' order')
              else:
                  params = self.omit(params, 'stopPrice')
                  request['stopPrice'] = self.price_to_precision(symbol, stopPrice)
          response = getattr(self, method)(self.extend(request, params))
          return self.parse_order(response, market)
  
      def fetch_order(self, id, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          defaultType = self.safe_string_2(self.options, 'fetchOrder', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          method = 'privateGetOrder'
          if type == 'future':
              method = 'fapiPrivateGetOrder'
          elif type == 'delivery':
              method = 'dapiPrivateGetOrder'
          elif type == 'margin':
              method = 'sapiGetMarginOrder'
          request = {
              'symbol': market['id'],
          }
          clientOrderId = self.safe_value_2(params, 'origClientOrderId', 'clientOrderId')
          if clientOrderId is not None:
              request['origClientOrderId'] = clientOrderId
          else:
              request['orderId'] = id
          query = self.omit(params, ['type', 'clientOrderId', 'origClientOrderId'])
          response = getattr(self, method)(self.extend(request, query))
          return self.parse_order(response, market)
  
      def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchOrders() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          defaultType = self.safe_string_2(self.options, 'fetchOrders', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          method = 'privateGetAllOrders'
          if type == 'future':
              method = 'fapiPrivateGetAllOrders'
          elif type == 'delivery':
              method = 'dapiPrivateGetAllOrders'
          elif type == 'margin':
              method = 'sapiGetMarginAllOrders'
          request = {
              'symbol': market['id'],
          }
          if since is not None:
              request['startTime'] = since
          if limit is not None:
              request['limit'] = limit
          query = self.omit(params, 'type')
          response = getattr(self, method)(self.extend(request, query))
          #
          #  spot
          #
          #     [
          #         {
          #             "symbol": "LTCBTC",
          #             "orderId": 1,
          #             "clientOrderId": "myOrder1",
          #             "price": "0.1",
          #             "origQty": "1.0",
          #             "executedQty": "0.0",
          #             "cummulativeQuoteQty": "0.0",
          #             "status": "NEW",
          #             "timeInForce": "GTC",
          #             "type": "LIMIT",
          #             "side": "BUY",
          #             "stopPrice": "0.0",
          #             "icebergQty": "0.0",
          #             "time": 1499827319559,
          #             "updateTime": 1499827319559,
          #             "isWorking": True
          #         }
          #     ]
          #
          #  futures
          #
          #     [
          #         {
          #             "symbol": "BTCUSDT",
          #             "orderId": 1,
          #             "clientOrderId": "myOrder1",
          #             "price": "0.1",
          #             "origQty": "1.0",
          #             "executedQty": "1.0",
          #             "cumQuote": "10.0",
          #             "status": "NEW",
          #             "timeInForce": "GTC",
          #             "type": "LIMIT",
          #             "side": "BUY",
          #             "stopPrice": "0.0",
          #             "updateTime": 1499827319559
          #         }
          #     ]
          #
          return self.parse_orders(response, market, since, limit)
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          market = None
          query = None
          type = None
          request = {}
          if symbol is not None:
              market = self.market(symbol)
              request['symbol'] = market['id']
              defaultType = self.safe_string_2(self.options, 'fetchOpenOrders', 'defaultType', 'spot')
              type = self.safe_string(params, 'type', defaultType)
              query = self.omit(params, 'type')
          elif self.options['warnOnFetchOpenOrdersWithoutSymbol']:
              symbols = self.symbols
              numSymbols = len(symbols)
              fetchOpenOrdersRateLimit = int(numSymbols / 2)
              raise ExchangeError(self.id + ' fetchOpenOrders WARNING: fetching open orders without specifying a symbol is rate-limited to one call per ' + str(fetchOpenOrdersRateLimit) + ' seconds. Do not call self method frequently to avoid ban. Set ' + self.id + '.options["warnOnFetchOpenOrdersWithoutSymbol"] = False to suppress self warning message.')
          else:
              defaultType = self.safe_string_2(self.options, 'fetchOpenOrders', 'defaultType', 'spot')
              type = self.safe_string(params, 'type', defaultType)
              query = self.omit(params, 'type')
          method = 'privateGetOpenOrders'
          if type == 'future':
              method = 'fapiPrivateGetOpenOrders'
          elif type == 'delivery':
              method = 'dapiPrivateGetOpenOrders'
          elif type == 'margin':
              method = 'sapiGetMarginOpenOrders'
          response = getattr(self, method)(self.extend(request, query))
          return self.parse_orders(response, market, since, limit)
  
      def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          orders = self.fetch_orders(symbol, since, limit, params)
          return self.filter_by(orders, 'status', 'closed')
  
      def cancel_order(self, id, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          defaultType = self.safe_string_2(self.options, 'fetchOpenOrders', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          # https://github.com/ccxt/ccxt/issues/6507
          origClientOrderId = self.safe_value_2(params, 'origClientOrderId', 'clientOrderId')
          request = {
              'symbol': market['id'],
              # 'orderId': id,
              # 'origClientOrderId': id,
          }
          if origClientOrderId is None:
              request['orderId'] = id
          else:
              request['origClientOrderId'] = origClientOrderId
          method = 'privateDeleteOrder'
          if type == 'future':
              method = 'fapiPrivateDeleteOrder'
          elif type == 'delivery':
              method = 'dapiPrivateDeleteOrder'
          elif type == 'margin':
              method = 'sapiDeleteMarginOrder'
          query = self.omit(params, ['type', 'origClientOrderId', 'clientOrderId'])
          response = getattr(self, method)(self.extend(request, query))
          return self.parse_order(response, market)
  
      def cancel_all_orders(self, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          defaultType = self.safe_string_2(self.options, 'cancelAllOrders', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          query = self.omit(params, 'type')
          method = 'privateDeleteOpenOrders'
          if type == 'margin':
              method = 'sapiDeleteMarginOpenOrders'
          elif type == 'future':
              method = 'fapiPrivateDeleteAllOpenOrders'
          elif type == 'delivery':
              method = 'dapiPrivateDeleteAllOpenOrders'
          response = getattr(self, method)(self.extend(request, query))
          if isinstance(response, list):
              return self.parse_orders(response, market)
          else:
              return response
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          defaultType = self.safe_string_2(self.options, 'fetchMyTrades', 'defaultType', 'spot')
          type = self.safe_string(params, 'type', defaultType)
          params = self.omit(params, 'type')
          method = None
          if type == 'spot':
              method = 'privateGetMyTrades'
          elif type == 'margin':
              method = 'sapiGetMarginMyTrades'
          elif type == 'future':
              method = 'fapiPrivateGetUserTrades'
          elif type == 'delivery':
              method = 'dapiPrivateGetUserTrades'
          request = {
              'symbol': market['id'],
          }
          if since is not None:
              request['startTime'] = since
          if limit is not None:
              request['limit'] = limit
          response = getattr(self, method)(self.extend(request, params))
          #
          # spot trade
          #
          #     [
          #         {
          #             "symbol": "BNBBTC",
          #             "id": 28457,
          #             "orderId": 100234,
          #             "price": "4.00000100",
          #             "qty": "12.00000000",
          #             "commission": "10.10000000",
          #             "commissionAsset": "BNB",
          #             "time": 1499865549590,
          #             "isBuyer": True,
          #             "isMaker": False,
          #             "isBestMatch": True,
          #         }
          #     ]
          #
          # futures trade
          #
          #     [
          #         {
          #             "accountId": 20,
          #             "buyer": False,
          #             "commission": "-0.07819010",
          #             "commissionAsset": "USDT",
          #             "counterPartyId": 653,
          #             "id": 698759,
          #             "maker": False,
          #             "orderId": 25851813,
          #             "price": "7819.01",
          #             "qty": "0.002",
          #             "quoteQty": "0.01563",
          #             "realizedPnl": "-0.91539999",
          #             "side": "SELL",
          #             "symbol": "BTCUSDT",
          #             "time": 1569514978020
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def fetch_my_dust_trades(self, symbol=None, since=None, limit=None, params={}):
          #
          # Binance provides an opportunity to trade insignificant(i.e. non-tradable and non-withdrawable)
          # token leftovers(of any asset) into `BNB` coin which in turn can be used to pay trading fees with it.
          # The corresponding trades history is called the `Dust Log` and can be requested via the following end-point:
          # https://github.com/binance-exchange/binance-official-api-docs/blob/master/wapi-api.md#dustlog-user_data
          #
          self.load_markets()
          request = {}
          if since is not None:
              request['startTime'] = since
              request['endTime'] = self.sum(since, 7776000000)
          response = self.sapiGetAssetDribblet(self.extend(request, params))
          #     {
          #       "total": "4",
          #       "userAssetDribblets": [
          #         {
          #           "operateTime": "1627575731000",
          #           "totalServiceChargeAmount": "0.00001453",
          #           "totalTransferedAmount": "0.00072693",
          #           "transId": "70899815863",
          #           "userAssetDribbletDetails": [
          #             {
          #               "fromAsset": "LTC",
          #               "amount": "0.000006",
          #               "transferedAmount": "0.00000267",
          #               "serviceChargeAmount": "0.00000005",
          #               "operateTime": "1627575731000",
          #               "transId": "70899815863"
          #             },
          #             {
          #               "fromAsset": "GBP",
          #               "amount": "0.15949157",
          #               "transferedAmount": "0.00072426",
          #               "serviceChargeAmount": "0.00001448",
          #               "operateTime": "1627575731000",
          #               "transId": "70899815863"
          #             }
          #           ]
          #         },
          #       ]
          #     }
          results = self.safe_value(response, 'userAssetDribblets', [])
          rows = self.safe_integer(response, 'total', 0)
          data = []
          for i in range(0, rows):
              logs = self.safe_value(results[i], 'userAssetDribbletDetails', [])
              for j in range(0, len(logs)):
                  logs[j]['isDustTrade'] = True
                  data.append(logs[j])
          trades = self.parse_trades(data, None, since, limit)
          return self.filter_by_since_limit(trades, since, limit)
  
      def parse_dust_trade(self, trade, market=None):
          #
          #     {
          #       "fromAsset": "USDT",
          #       "amount": "0.009669",
          #       "transferedAmount": "0.00002992",
          #       "serviceChargeAmount": "0.00000059",
          #       "operateTime": "1628076010000",
          #       "transId": "71416578712",
          #       "isDustTrade": True
          #     }
          #
          orderId = self.safe_string(trade, 'transId')
          timestamp = self.safe_integer(trade, 'operateTime')
          currencyId = self.safe_string(trade, 'fromAsset')
          tradedCurrency = self.safe_currency_code(currencyId)
          bnb = self.currency('BNB')
          earnedCurrency = bnb['code']
          applicantSymbol = earnedCurrency + '/' + tradedCurrency
          tradedCurrencyIsQuote = False
          if applicantSymbol in self.markets:
              tradedCurrencyIsQuote = True
          feeCostString = self.safe_string(trade, 'serviceChargeAmount')
          fee = {
              'currency': earnedCurrency,
              'cost': self.parse_number(feeCostString),
          }
          symbol = None
          amountString = None
          costString = None
          side = None
          if tradedCurrencyIsQuote:
              symbol = applicantSymbol
              amountString = self.safe_string(trade, 'transferedAmount')
              costString = self.safe_string(trade, 'amount')
              side = 'buy'
          else:
              symbol = tradedCurrency + '/' + earnedCurrency
              amountString = self.safe_string(trade, 'amount')
              costString = self.safe_string(trade, 'transferedAmount')
              side = 'sell'
          priceString = None
          if costString is not None:
              if amountString:
                  priceString = Precise.string_div(costString, amountString)
          id = None
          amount = self.parse_number(amountString)
          price = self.parse_number(priceString)
          cost = self.parse_number(costString)
          type = None
          takerOrMaker = None
          return {
              'id': id,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'order': orderId,
              'type': type,
              'takerOrMaker': takerOrMaker,
              'side': side,
              'amount': amount,
              'price': price,
              'cost': cost,
              'fee': fee,
              'info': trade,
          }
  
      def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          currency = None
          response = None
          request = {}
          legalMoney = self.safe_value(self.options, 'legalMoney', {})
          if code in legalMoney:
              if code is not None:
                  currency = self.currency(code)
              request['transactionType'] = 0
              if since is not None:
                  request['beginTime'] = since
              raw = self.sapiGetFiatOrders(self.extend(request, params))
              response = self.safe_value(raw, 'data')
              #     {
              #       "code": "000000",
              #       "message": "success",
              #       "data": [
              #         {
              #           "orderNo": "25ced37075c1470ba8939d0df2316e23",
              #           "fiatCurrency": "EUR",
              #           "indicatedAmount": "15.00",
              #           "amount": "15.00",
              #           "totalFee": "0.00",
              #           "method": "card",
              #           "status": "Failed",
              #           "createTime": 1627501026000,
              #           "updateTime": 1627501027000
              #         }
              #       ],
              #       "total": 1,
              #       "success": True
              #     }
          else:
              if code is not None:
                  currency = self.currency(code)
                  request['coin'] = currency['id']
              if since is not None:
                  request['startTime'] = since
                  # max 3 months range https://github.com/ccxt/ccxt/issues/6495
                  request['endTime'] = self.sum(since, 7776000000)
              if limit is not None:
                  request['limit'] = limit
              response = self.sapiGetCapitalDepositHisrec(self.extend(request, params))
              #     [
              #       {
              #         "amount": "0.01844487",
              #         "coin": "BCH",
              #         "network": "BCH",
              #         "status": 1,
              #         "address": "1NYxAJhW2281HK1KtJeaENBqHeygA88FzR",
              #         "addressTag": "",
              #         "txId": "bafc5902504d6504a00b7d0306a41154cbf1d1b767ab70f3bc226327362588af",
              #         "insertTime": 1610784980000,
              #         "transferType": 0,
              #         "confirmTimes": "2/2"
              #       },
              #       {
              #         "amount": "4500",
              #         "coin": "USDT",
              #         "network": "BSC",
              #         "status": 1,
              #         "address": "0xc9c923c87347ca0f3451d6d308ce84f691b9f501",
              #         "addressTag": "",
              #         "txId": "Internal transfer 51376627901",
              #         "insertTime": 1618394381000,
              #         "transferType": 1,
              #         "confirmTimes": "1/15"
              #     }
              #   ]
          return self.parse_transactions(response, currency, since, limit)
  
      def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          legalMoney = self.safe_value(self.options, 'legalMoney', {})
          request = {}
          response = None
          currency = None
          if code in legalMoney:
              if code is not None:
                  currency = self.currency(code)
              request['transactionType'] = 1
              if since is not None:
                  request['beginTime'] = since
              raw = self.sapiGetFiatOrders(self.extend(request, params))
              response = self.safe_value(raw, 'data')
              #     {
              #       "code": "000000",
              #       "message": "success",
              #       "data": [
              #         {
              #           "orderNo": "CJW706452266115170304",
              #           "fiatCurrency": "GBP",
              #           "indicatedAmount": "10001.50",
              #           "amount": "100.00",
              #           "totalFee": "1.50",
              #           "method": "bank transfer",
              #           "status": "Successful",
              #           "createTime": 1620037745000,
              #           "updateTime": 1620038480000
              #         },
              #         {
              #           "orderNo": "CJW706287492781891584",
              #           "fiatCurrency": "GBP",
              #           "indicatedAmount": "10001.50",
              #           "amount": "100.00",
              #           "totalFee": "1.50",
              #           "method": "bank transfer",
              #           "status": "Successful",
              #           "createTime": 1619998460000,
              #           "updateTime": 1619998823000
              #         }
              #       ],
              #       "total": 39,
              #       "success": True
              #     }
          else:
              if code is not None:
                  currency = self.currency(code)
                  request['coin'] = currency['id']
              if since is not None:
                  request['startTime'] = since
                  # max 3 months range https://github.com/ccxt/ccxt/issues/6495
                  request['endTime'] = self.sum(since, 7776000000)
              if limit is not None:
                  request['limit'] = limit
              response = self.sapiGetCapitalWithdrawHistory(self.extend(request, params))
              #     [
              #       {
              #         "id": "69e53ad305124b96b43668ceab158a18",
              #         "amount": "28.75",
              #         "transactionFee": "0.25",
              #         "coin": "XRP",
              #         "status": 6,
              #         "address": "r3T75fuLjX51mmfb5Sk1kMNuhBgBPJsjza",
              #         "addressTag": "101286922",
              #         "txId": "19A5B24ED0B697E4F0E9CD09FCB007170A605BC93C9280B9E6379C5E6EF0F65A",
              #         "applyTime": "2021-04-15 12:09:16",
              #         "network": "XRP",
              #         "transferType": 0
              #       },
              #       {
              #         "id": "9a67628b16ba4988ae20d329333f16bc",
              #         "amount": "20",
              #         "transactionFee": "20",
              #         "coin": "USDT",
              #         "status": 6,
              #         "address": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
              #         "txId": "0x77fbf2cf2c85b552f0fd31fd2e56dc95c08adae031d96f3717d8b17e1aea3e46",
              #         "applyTime": "2021-04-15 12:06:53",
              #         "network": "ETH",
              #         "transferType": 0
              #       },
              #       {
              #         "id": "a7cdc0afbfa44a48bd225c9ece958fe2",
              #         "amount": "51",
              #         "transactionFee": "1",
              #         "coin": "USDT",
              #         "status": 6,
              #         "address": "TYDmtuWL8bsyjvcauUTerpfYyVhFtBjqyo",
              #         "txId": "168a75112bce6ceb4823c66726ad47620ad332e69fe92d9cb8ceb76023f9a028",
              #         "applyTime": "2021-04-13 12:46:59",
              #         "network": "TRX",
              #         "transferType": 0
              #       }
              #     ]
          return self.parse_transactions(response, currency, since, limit)
  
      def parse_transaction_status_by_type(self, status, type=None):
          statusesByType = {
              'deposit': {
                  '0': 'pending',
                  '1': 'ok',
                  # Fiat
                  # Processing, Failed, Successful, Finished, Refunding, Refunded, Refund Failed, Order Partial credit Stopped
                  'Processing': 'pending',
                  'Failed': 'failed',
                  'Successful': 'ok',
                  'Refunding': 'canceled',
                  'Refunded': 'canceled',
                  'Refund Failed': 'failed',
              },
              'withdrawal': {
                  '0': 'pending',  # Email Sent
                  '1': 'canceled',  # Cancelled(different from 1 = ok in deposits)
                  '2': 'pending',  # Awaiting Approval
                  '3': 'failed',  # Rejected
                  '4': 'pending',  # Processing
                  '5': 'failed',  # Failure
                  '6': 'ok',  # Completed
                  # Fiat
                  # Processing, Failed, Successful, Finished, Refunding, Refunded, Refund Failed, Order Partial credit Stopped
                  'Processing': 'pending',
                  'Failed': 'failed',
                  'Successful': 'ok',
                  'Refunding': 'canceled',
                  'Refunded': 'canceled',
                  'Refund Failed': 'failed',
              },
          }
          statuses = self.safe_value(statusesByType, type, {})
          return self.safe_string(statuses, status, status)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchDeposits
          #
          #     {
          #       "amount": "4500",
          #       "coin": "USDT",
          #       "network": "BSC",
          #       "status": 1,
          #       "address": "0xc9c923c87347ca0f3451d6d308ce84f691b9f501",
          #       "addressTag": "",
          #       "txId": "Internal transfer 51376627901",
          #       "insertTime": 1618394381000,
          #       "transferType": 1,
          #       "confirmTimes": "1/15"
          #     }
          #
          # fetchWithdrawals
          #
          #     {
          #       "id": "69e53ad305124b96b43668ceab158a18",
          #       "amount": "28.75",
          #       "transactionFee": "0.25",
          #       "coin": "XRP",
          #       "status": 6,
          #       "address": "r3T75fuLjX51mmfb5Sk1kMNuhBgBPJsjza",
          #       "addressTag": "101286922",
          #       "txId": "19A5B24ED0B697E4F0E9CD09FCB007170A605BC93C9280B9E6379C5E6EF0F65A",
          #       "applyTime": "2021-04-15 12:09:16",
          #       "network": "XRP",
          #       "transferType": 0
          #     }
          #
          # fiat transaction
          # withdraw
          #     {
          #       "orderNo": "CJW684897551397171200",
          #       "fiatCurrency": "GBP",
          #       "indicatedAmount": "29.99",
          #       "amount": "28.49",
          #       "totalFee": "1.50",
          #       "method": "bank transfer",
          #       "status": "Successful",
          #       "createTime": 1614898701000,
          #       "updateTime": 1614898820000
          #     }
          #
          # deposit
          #     {
          #       "orderNo": "25ced37075c1470ba8939d0df2316e23",
          #       "fiatCurrency": "EUR",
          #       "indicatedAmount": "15.00",
          #       "amount": "15.00",
          #       "totalFee": "0.00",
          #       "method": "card",
          #       "status": "Failed",
          #       "createTime": "1627501026000",
          #       "updateTime": "1627501027000"
          #     }
          #
          id = self.safe_string_2(transaction, 'id', 'orderNo')
          address = self.safe_string(transaction, 'address')
          tag = self.safe_string(transaction, 'addressTag')  # set but unused
          if tag is not None:
              if len(tag) < 1:
                  tag = None
          txid = self.safe_string(transaction, 'txId')
          if (txid is not None) and (txid.find('Internal transfer ') >= 0):
              txid = txid[18:]
          currencyId = self.safe_string_2(transaction, 'coin', 'fiatCurrency')
          code = self.safe_currency_code(currencyId, currency)
          timestamp = None
          insertTime = self.safe_integer_2(transaction, 'insertTime', 'createTime')
          applyTime = self.parse8601(self.safe_string(transaction, 'applyTime'))
          type = self.safe_string(transaction, 'type')
          if type is None:
              if (insertTime is not None) and (applyTime is None):
                  type = 'deposit'
                  timestamp = insertTime
              elif (insertTime is None) and (applyTime is not None):
                  type = 'withdrawal'
                  timestamp = applyTime
          status = self.parse_transaction_status_by_type(self.safe_string(transaction, 'status'), type)
          amount = self.safe_number(transaction, 'amount')
          feeCost = self.safe_number_2(transaction, 'transactionFee', 'totalFee')
          fee = None
          if feeCost is not None:
              fee = {'currency': code, 'cost': feeCost}
          updated = self.safe_integer_2(transaction, 'successTime', 'updateTime')
          internal = self.safe_integer(transaction, 'transferType', False)
          internal = True if internal else False
          return {
              'info': transaction,
              'id': id,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'address': address,
              'addressTo': address,
              'addressFrom': None,
              'tag': tag,
              'tagTo': tag,
              'tagFrom': None,
              'type': type,
              'amount': amount,
              'currency': code,
              'status': status,
              'updated': updated,
              'internal': internal,
              'fee': fee,
          }
  
      def parse_transfer_status(self, status):
          statuses = {
              'CONFIRMED': 'ok',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transfer(self, transfer, currency=None):
          #
          # transfer
          #
          #     {
          #         "tranId":13526853623
          #     }
          #
          # fetchTransfers
          #
          #     {
          #         timestamp: 1614640878000,
          #         asset: 'USDT',
          #         amount: '25',
          #         type: 'MAIN_UMFUTURE',
          #         status: 'CONFIRMED',
          #         tranId: 43000126248
          #     }
          #
          id = self.safe_string(transfer, 'tranId')
          currencyId = self.safe_string(transfer, 'asset')
          code = self.safe_currency_code(currencyId, currency)
          amount = self.safe_number(transfer, 'amount')
          type = self.safe_string(transfer, 'type')
          fromAccount = None
          toAccount = None
          typesByAccount = self.safe_value(self.options, 'typesByAccount', {})
          if type is not None:
              parts = type.split('_')
              fromAccount = self.safe_value(parts, 0)
              toAccount = self.safe_value(parts, 1)
              fromAccount = self.safe_string(typesByAccount, fromAccount, fromAccount)
              toAccount = self.safe_string(typesByAccount, toAccount, toAccount)
          timestamp = self.safe_integer(transfer, 'timestamp')
          status = self.parse_transfer_status(self.safe_string(transfer, 'status'))
          return {
              'info': transfer,
              'id': id,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'currency': code,
              'amount': amount,
              'fromAccount': fromAccount,
              'toAccount': toAccount,
              'status': status,
          }
  
      def parse_income(self, income, market=None):
          #
          #     {
          #       "symbol": "ETHUSDT",
          #       "incomeType": "FUNDING_FEE",
          #       "income": "0.00134317",
          #       "asset": "USDT",
          #       "time": "1621584000000",
          #       "info": "FUNDING_FEE",
          #       "tranId": "4480321991774044580",
          #       "tradeId": ""
          #     }
          #
          marketId = self.safe_string(income, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          amount = self.safe_number(income, 'income')
          currencyId = self.safe_string(income, 'asset')
          code = self.safe_currency_code(currencyId)
          id = self.safe_string(income, 'tranId')
          timestamp = self.safe_integer(income, 'time')
          return {
              'info': income,
              'symbol': symbol,
              'code': code,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'id': id,
              'amount': amount,
          }
  
      def parse_incomes(self, incomes, market=None, since=None, limit=None):
          result = []
          for i in range(0, len(incomes)):
              entry = incomes[i]
              parsed = self.parse_income(entry, market)
              result.append(parsed)
          sorted = self.sort_by(result, 'timestamp')
          return self.filter_by_since_limit(sorted, since, limit)
  
      def transfer(self, code, amount, fromAccount, toAccount, params={}):
          self.load_markets()
          currency = self.currency(code)
          fromAccount = fromAccount.lower()
          toAccount = toAccount.lower()
          type = self.safe_string(params, 'type')
          if type is None:
              accountsByType = self.safe_value(self.options, 'accountsByType', {})
              fromId = self.safe_string(accountsByType, fromAccount)
              toId = self.safe_string(accountsByType, toAccount)
              if fromId is None:
                  keys = list(accountsByType.keys())
                  raise ExchangeError(self.id + ' fromAccount must be one of ' + ', '.join(keys))
              if toId is None:
                  keys = list(accountsByType.keys())
                  raise ExchangeError(self.id + ' toAccount must be one of ' + ', '.join(keys))
              type = fromId + '_' + toId
          request = {
              'asset': currency['id'],
              'amount': self.currency_to_precision(code, amount),
              'type': type,
          }
          response = self.sapiPostAssetTransfer(self.extend(request, params))
          #
          #     {
          #         "tranId":13526853623
          #     }
          #
          transfer = self.parse_transfer(response, currency)
          return self.extend(transfer, {
              'amount': amount,
              'currency': code,
              'fromAccount': fromAccount,
              'toAccount': toAccount,
          })
  
      def fetch_transfers(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          currency = None
          if code is not None:
              currency = self.currency(code)
          defaultType = self.safe_string_2(self.options, 'fetchTransfers', 'defaultType', 'spot')
          fromAccount = self.safe_string(params, 'fromAccount', defaultType)
          defaultTo = 'spot' if (fromAccount == 'future') else 'future'
          toAccount = self.safe_string(params, 'toAccount', defaultTo)
          type = self.safe_string(params, 'type')
          accountsByType = self.safe_value(self.options, 'accountsByType', {})
          fromId = self.safe_string(accountsByType, fromAccount)
          toId = self.safe_string(accountsByType, toAccount)
          if type is None:
              if fromId is None:
                  keys = list(accountsByType.keys())
                  raise ExchangeError(self.id + ' fromAccount parameter must be one of ' + ', '.join(keys))
              if toId is None:
                  keys = list(accountsByType.keys())
                  raise ExchangeError(self.id + ' toAccount parameter must be one of ' + ', '.join(keys))
              type = fromId + '_' + toId
          request = {
              'type': type,
          }
          if since is not None:
              request['startTime'] = since
          if limit is not None:
              request['size'] = limit
          response = self.sapiGetAssetTransfer(self.extend(request, params))
          #
          #     {
          #         total: 3,
          #         rows: [
          #             {
          #                 timestamp: 1614640878000,
          #                 asset: 'USDT',
          #                 amount: '25',
          #                 type: 'MAIN_UMFUTURE',
          #                 status: 'CONFIRMED',
          #                 tranId: 43000126248
          #             },
          #         ]
          #     }
          #
          rows = self.safe_value(response, 'rows', [])
          return self.parse_transfers(rows, currency, since, limit)
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'coin': currency['id'],
              # 'network': 'ETH',  # 'BSC', 'XMR', you can get network and isDefault in networkList in the response of sapiGetCapitalConfigDetail
          }
          networks = self.safe_value(self.options, 'networks', {})
          network = self.safe_string_upper(params, 'network')  # self line allows the user to specify either ERC20 or ETH
          network = self.safe_string(networks, network, network)  # handle ERC20>ETH alias
          if network is not None:
              request['network'] = network
              params = self.omit(params, 'network')
          # has support for the 'network' parameter
          # https://binance-docs.github.io/apidocs/spot/en/#deposit-address-supporting-network-user_data
          response = self.sapiGetCapitalDepositAddress(self.extend(request, params))
          #
          #     {
          #         currency: 'XRP',
          #         address: 'rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh',
          #         tag: '108618262',
          #         info: {
          #             coin: 'XRP',
          #             address: 'rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh',
          #             tag: '108618262',
          #             url: 'https://bithomp.com/explorer/rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh'
          #         }
          #     }
          #
          address = self.safe_string(response, 'address')
          url = self.safe_string(response, 'url')
          impliedNetwork = None
          if url is not None:
              reverseNetworks = self.safe_value(self.options, 'reverseNetworks', {})
              parts = url.split('/')
              topLevel = self.safe_string(parts, 2)
              if (topLevel == 'blockchair.com') or (topLevel == 'viewblock.io'):
                  subLevel = self.safe_string(parts, 3)
                  if subLevel is not None:
                      topLevel = topLevel + '/' + subLevel
              impliedNetwork = self.safe_string(reverseNetworks, topLevel)
              impliedNetworks = self.safe_value(self.options, 'impliedNetworks', {
                  'ETH': {'ERC20': 'ETH'},
                  'TRX': {'TRC20': 'TRX'},
              })
              if code in impliedNetworks:
                  conversion = self.safe_value(impliedNetworks, code, {})
                  impliedNetwork = self.safe_string(conversion, impliedNetwork, impliedNetwork)
          tag = self.safe_string(response, 'tag', '')
          if len(tag) == 0:
              tag = None
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'tag': tag,
              'network': impliedNetwork,
              'info': response,
          }
  
      def fetch_funding_fees(self, codes=None, params={}):
          self.load_markets()
          response = self.sapiGetCapitalConfigGetall(params)
          #
          #  [
          #     {
          #       coin: 'BAT',
          #       depositAllEnable: True,
          #       withdrawAllEnable: True,
          #       name: 'Basic Attention Token',
          #       free: '0',
          #       locked: '0',
          #       freeze: '0',
          #       withdrawing: '0',
          #       ipoing: '0',
          #       ipoable: '0',
          #       storage: '0',
          #       isLegalMoney: False,
          #       trading: True,
          #       networkList: [
          #         {
          #           network: 'BNB',
          #           coin: 'BAT',
          #           withdrawIntegerMultiple: '0.00000001',
          #           isDefault: False,
          #           depositEnable: True,
          #           withdrawEnable: True,
          #           depositDesc: '',
          #           withdrawDesc: '',
          #           specialTips: 'The name of self asset is Basic Attention Token(BAT). Both a MEMO and an Address are required to successfully deposit your BEP2 tokens to Binance.',
          #           name: 'BEP2',
          #           resetAddressStatus: False,
          #           addressRegex: '^(bnb1)[0-9a-z]{38}$',
          #           memoRegex: '^[0-9A-Za-z\\-_]{1,120}$',
          #           withdrawFee: '0.27',
          #           withdrawMin: '0.54',
          #           withdrawMax: '10000000000',
          #           minConfirm: '1',
          #           unLockConfirm: '0'
          #         },
          #         {
          #           network: 'BSC',
          #           coin: 'BAT',
          #           withdrawIntegerMultiple: '0.00000001',
          #           isDefault: False,
          #           depositEnable: True,
          #           withdrawEnable: True,
          #           depositDesc: '',
          #           withdrawDesc: '',
          #           specialTips: 'The name of self asset is Basic Attention Token. Please ensure you are depositing Basic Attention Token(BAT) tokens under the contract address ending in 9766e.',
          #           name: 'BEP20(BSC)',
          #           resetAddressStatus: False,
          #           addressRegex: '^(0x)[0-9A-Fa-f]{40}$',
          #           memoRegex: '',
          #           withdrawFee: '0.27',
          #           withdrawMin: '0.54',
          #           withdrawMax: '10000000000',
          #           minConfirm: '15',
          #           unLockConfirm: '0'
          #         },
          #         {
          #           network: 'ETH',
          #           coin: 'BAT',
          #           withdrawIntegerMultiple: '0.00000001',
          #           isDefault: True,
          #           depositEnable: True,
          #           withdrawEnable: True,
          #           depositDesc: '',
          #           withdrawDesc: '',
          #           specialTips: 'The name of self asset is Basic Attention Token. Please ensure you are depositing Basic Attention Token(BAT) tokens under the contract address ending in 887ef.',
          #           name: 'ERC20',
          #           resetAddressStatus: False,
          #           addressRegex: '^(0x)[0-9A-Fa-f]{40}$',
          #           memoRegex: '',
          #           withdrawFee: '27',
          #           withdrawMin: '54',
          #           withdrawMax: '10000000000',
          #           minConfirm: '12',
          #           unLockConfirm: '0'
          #         }
          #       ]
          #     }
          #  ]
          #
          withdrawFees = {}
          for i in range(0, len(response)):
              entry = response[i]
              currencyId = self.safe_string(entry, 'coin')
              code = self.safe_currency_code(currencyId)
              networkList = self.safe_value(entry, 'networkList')
              withdrawFees[code] = {}
              for j in range(0, len(networkList)):
                  networkEntry = networkList[j]
                  networkId = self.safe_string(networkEntry, 'network')
                  networkCode = self.safe_currency_code(networkId)
                  fee = self.safe_number(networkEntry, 'withdrawFee')
                  withdrawFees[code][networkCode] = fee
          return {
              'withdraw': withdrawFees,
              'deposit': {},
              'info': response,
          }
  
      def withdraw(self, code, amount, address, tag=None, params={}):
          tag, params = self.handle_withdraw_tag_and_params(tag, params)
          self.check_address(address)
          self.load_markets()
          currency = self.currency(code)
          request = {
              'coin': currency['id'],
              'address': address,
              'amount': amount,
              # https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi
              # issue sapiGetCapitalConfigGetall() to get networks for withdrawing USDT ERC20 vs USDT Omni
              # 'network': 'ETH',  # 'BTC', 'TRX', etc, optional
          }
          if tag is not None:
              request['addressTag'] = tag
          networks = self.safe_value(self.options, 'networks', {})
          network = self.safe_string_upper(params, 'network')  # self line allows the user to specify either ERC20 or ETH
          network = self.safe_string(networks, network, network)  # handle ERC20>ETH alias
          if network is not None:
              request['network'] = network
              params = self.omit(params, 'network')
          response = self.sapiPostCapitalWithdrawApply(self.extend(request, params))
          #     {id: '9a67628b16ba4988ae20d329333f16bc'}
          return {
              'info': response,
              'id': self.safe_string(response, 'id'),
          }
  
      def parse_trading_fee(self, fee, market=None):
          #
          #     {
          #         "symbol": "ADABNB",
          #         "makerCommission": 0.001,
          #         "takerCommission": 0.001
          #     }
          #
          marketId = self.safe_string(fee, 'symbol')
          symbol = self.safe_symbol(marketId)
          return {
              'info': fee,
              'symbol': symbol,
              'maker': self.safe_number(fee, 'makerCommission'),
              'taker': self.safe_number(fee, 'takerCommission'),
          }
  
      def fetch_trading_fee(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          response = self.sapiGetAssetTradeFee(self.extend(request, params))
          #
          #     [
          #       {
          #         "symbol": "BTCUSDT",
          #         "makerCommission": "0.001",
          #         "takerCommission": "0.001"
          #       }
          #     ]
          #
          first = self.safe_value(response, 0, {})
          return self.parse_trading_fee(first)
  
      def fetch_trading_fees(self, params={}):
          self.load_markets()
          method = None
          defaultType = self.safe_string_2(self.options, 'fetchFundingRates', 'defaultType', 'future')
          type = self.safe_string(params, 'type', defaultType)
          query = self.omit(params, 'type')
          if (type == 'spot') or (type == 'margin'):
              method = 'sapiGetAssetTradeFee'
          elif type == 'future':
              method = 'fapiPrivateGetAccount'
          elif type == 'delivery':
              method = 'dapiPrivateGetAccount'
          response = getattr(self, method)(query)
          #
          # sapi / spot
          #
          #    [
          #       {
          #         "symbol": "ZRXBNB",
          #         "makerCommission": "0.001",
          #         "takerCommission": "0.001"
          #       },
          #       {
          #         "symbol": "ZRXBTC",
          #         "makerCommission": "0.001",
          #         "takerCommission": "0.001"
          #       },
          #    ]
          #
          # fapi / future / linear
          #
          #     {
          #         "feeTier": 0,       # account commisssion tier
          #         "canTrade": True,   # if can trade
          #         "canDeposit": True,     # if can transfer in asset
          #         "canWithdraw": True,    # if can transfer out asset
          #         "updateTime": 0,
          #         "totalInitialMargin": "0.00000000",    # total initial margin required with current mark price(useless with isolated positions), only for USDT asset
          #         "totalMaintMargin": "0.00000000",     # total maintenance margin required, only for USDT asset
          #         "totalWalletBalance": "23.72469206",     # total wallet balance, only for USDT asset
          #         "totalUnrealizedProfit": "0.00000000",   # total unrealized profit, only for USDT asset
          #         "totalMarginBalance": "23.72469206",     # total margin balance, only for USDT asset
          #         "totalPositionInitialMargin": "0.00000000",    # initial margin required for positions with current mark price, only for USDT asset
          #         "totalOpenOrderInitialMargin": "0.00000000",   # initial margin required for open orders with current mark price, only for USDT asset
          #         "totalCrossWalletBalance": "23.72469206",      # crossed wallet balance, only for USDT asset
          #         "totalCrossUnPnl": "0.00000000",      # unrealized profit of crossed positions, only for USDT asset
          #         "availableBalance": "23.72469206",       # available balance, only for USDT asset
          #         "maxWithdrawAmount": "23.72469206"     # maximum amount for transfer out, only for USDT asset
          #         ...
          #     }
          #
          # dapi / delivery / inverse
          #
          #     {
          #         "canDeposit": True,
          #         "canTrade": True,
          #         "canWithdraw": True,
          #         "feeTier": 2,
          #         "updateTime": 0
          #     }
          #
          if (type == 'spot') or (type == 'margin'):
              #
              #    [
              #       {
              #         "symbol": "ZRXBNB",
              #         "makerCommission": "0.001",
              #         "takerCommission": "0.001"
              #       },
              #       {
              #         "symbol": "ZRXBTC",
              #         "makerCommission": "0.001",
              #         "takerCommission": "0.001"
              #       },
              #    ]
              #
              result = {}
              for i in range(0, len(response)):
                  fee = self.parse_trading_fee(response[i])
                  symbol = fee['symbol']
                  result[symbol] = fee
              return result
          elif type == 'future':
              #
              #     {
              #         "feeTier": 0,       # account commisssion tier
              #         "canTrade": True,   # if can trade
              #         "canDeposit": True,     # if can transfer in asset
              #         "canWithdraw": True,    # if can transfer out asset
              #         "updateTime": 0,
              #         "totalInitialMargin": "0.00000000",    # total initial margin required with current mark price(useless with isolated positions), only for USDT asset
              #         "totalMaintMargin": "0.00000000",     # total maintenance margin required, only for USDT asset
              #         "totalWalletBalance": "23.72469206",     # total wallet balance, only for USDT asset
              #         "totalUnrealizedProfit": "0.00000000",   # total unrealized profit, only for USDT asset
              #         "totalMarginBalance": "23.72469206",     # total margin balance, only for USDT asset
              #         "totalPositionInitialMargin": "0.00000000",    # initial margin required for positions with current mark price, only for USDT asset
              #         "totalOpenOrderInitialMargin": "0.00000000",   # initial margin required for open orders with current mark price, only for USDT asset
              #         "totalCrossWalletBalance": "23.72469206",      # crossed wallet balance, only for USDT asset
              #         "totalCrossUnPnl": "0.00000000",      # unrealized profit of crossed positions, only for USDT asset
              #         "availableBalance": "23.72469206",       # available balance, only for USDT asset
              #         "maxWithdrawAmount": "23.72469206"     # maximum amount for transfer out, only for USDT asset
              #         ...
              #     }
              #
              symbols = list(self.markets.keys())
              result = {}
              feeTier = self.safe_integer(response, 'feeTier')
              feeTiers = self.fees[type]['trading']['tiers']
              maker = feeTiers['maker'][feeTier][1]
              taker = feeTiers['taker'][feeTier][1]
              for i in range(0, len(symbols)):
                  symbol = symbols[i]
                  result[symbol] = {
                      'info': {
                          'feeTier': feeTier,
                      },
                      'symbol': symbol,
                      'maker': maker,
                      'taker': taker,
                  }
              return result
          elif type == 'delivery':
              #
              #     {
              #         "canDeposit": True,
              #         "canTrade": True,
              #         "canWithdraw": True,
              #         "feeTier": 2,
              #         "updateTime": 0
              #     }
              #
              symbols = list(self.markets.keys())
              result = {}
              feeTier = self.safe_integer(response, 'feeTier')
              feeTiers = self.fees[type]['trading']['tiers']
              maker = feeTiers['maker'][feeTier][1]
              taker = feeTiers['taker'][feeTier][1]
              for i in range(0, len(symbols)):
                  symbol = symbols[i]
                  result[symbol] = {
                      'info': {
                          'feeTier': feeTier,
                      },
                      'symbol': symbol,
                      'maker': maker,
                      'taker': taker,
                  }
              return result
  
      def futures_transfer(self, code, amount, type, params={}):
          if (type < 1) or (type > 4):
              raise ArgumentsRequired(self.id + ' type must be between 1 and 4')
          self.load_markets()
          currency = self.currency(code)
          request = {
              'asset': currency['id'],
              'amount': amount,
              'type': type,
          }
          response = self.sapiPostFuturesTransfer(self.extend(request, params))
          #
          #   {
          #       "tranId": 100000001
          #   }
          #
          return self.parse_transfer(response, currency)
  
      def fetch_funding_rate(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          method = None
          if market['linear']:
              method = 'fapiPublicGetPremiumIndex'
          elif market['inverse']:
              method = 'dapiPublicGetPremiumIndex'
          else:
              raise NotSupported(self.id + ' fetchFundingRate() supports linear and inverse contracts only')
          response = getattr(self, method)(self.extend(request, params))
          if market['inverse']:
              response = response[0]
          #
          #     {
          #         "symbol": "BTCUSDT",
          #         "markPrice": "45802.81129892",
          #         "indexPrice": "45745.47701915",
          #         "estimatedSettlePrice": "45133.91753671",
          #         "lastFundingRate": "0.00063521",
          #         "interestRate": "0.00010000",
          #         "nextFundingTime": "1621267200000",
          #         "time": "1621252344001"
          #     }
          #
          return self.parse_funding_rate(response, market)
  
      def fetch_funding_rate_history(self, symbol=None, since=None, limit=None, params={}):
          #
          # Gets a history of funding rates with their timestamps
          #  (param) symbol: Future currency pair(e.g. "BTC/USDT")
          #  (param) limit: maximum number of data points returned
          #  (param) since: Unix timestamp in miliseconds for the time of the earliest requested funding rate
          #  (param) params: Object containing more params for the request
          #          - until: Unix timestamp in miliseconds for the time of the earliest requested funding rate
          #  return: [{symbol, fundingRate, timestamp}]
          #
          self.load_markets()
          request = {}
          method = None
          defaultType = self.safe_string_2(self.options, 'fetchFundingRateHistory', 'defaultType', 'future')
          type = self.safe_string(params, 'type', defaultType)
          params = self.omit(params, 'type')
          if type == 'future':
              method = 'fapiPublicGetFundingRate'
          elif type == 'delivery':
              method = 'dapiPublicGetFundingRate'
          if symbol is not None:
              market = self.market(symbol)
              request['symbol'] = market['id']
              if market['linear']:
                  method = 'fapiPublicGetFundingRate'
              elif market['inverse']:
                  method = 'dapiPublicGetFundingRate'
          if method is None:
              raise NotSupported(self.id + ' fetchFundingRateHistory() not supported for ' + type + ' markets')
          if since is not None:
              request['startTime'] = since
          till = self.safe_integer(params, 'till')  # unified in milliseconds
          endTime = self.safe_string(params, 'endTime', till)  # exchange-specific in milliseconds
          params = self.omit(params, ['endTime', 'till'])
          if endTime is not None:
              request['endTime'] = endTime
          if limit is not None:
              request['limit'] = limit
          response = getattr(self, method)(self.extend(request, params))
          #
          #     {
          #         "symbol": "BTCUSDT",
          #         "fundingRate": "0.00063521",
          #         "fundingTime": "1621267200000",
          #     }
          #
          rates = []
          for i in range(0, len(response)):
              entry = response[i]
              timestamp = self.safe_integer(entry, 'fundingTime')
              rates.append({
                  'info': entry,
                  'symbol': self.safe_symbol(self.safe_string(entry, 'symbol')),
                  'fundingRate': self.safe_number(entry, 'fundingRate'),
                  'timestamp': timestamp,
                  'datetime': self.iso8601(timestamp),
              })
          sorted = self.sort_by(rates, 'timestamp')
          return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
  
      def fetch_funding_rates(self, symbols=None, params={}):
          self.load_markets()
          method = None
          defaultType = self.safe_string_2(self.options, 'fetchFundingRates', 'defaultType', 'future')
          type = self.safe_string(params, 'type', defaultType)
          query = self.omit(params, 'type')
          if type == 'future':
              method = 'fapiPublicGetPremiumIndex'
          elif type == 'delivery':
              method = 'dapiPublicGetPremiumIndex'
          else:
              raise NotSupported(self.id + ' fetchFundingRates() supports linear and inverse contracts only')
          response = getattr(self, method)(query)
          result = []
          for i in range(0, len(response)):
              entry = response[i]
              parsed = self.parse_funding_rate(entry)
              result.append(parsed)
          return self.filter_by_array(result, 'symbol', symbols)
  
      def parse_funding_rate(self, premiumIndex, market=None):
          # ensure it matches with https://www.binance.com/en/futures/funding-history/0
          #
          #   {
          #     "symbol": "BTCUSDT",
          #     "markPrice": "45802.81129892",
          #     "indexPrice": "45745.47701915",
          #     "estimatedSettlePrice": "45133.91753671",
          #     "lastFundingRate": "0.00063521",
          #     "interestRate": "0.00010000",
          #     "nextFundingTime": "1621267200000",
          #     "time": "1621252344001"
          #  }
          #
          timestamp = self.safe_integer(premiumIndex, 'time')
          marketId = self.safe_string(premiumIndex, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          markPrice = self.safe_number(premiumIndex, 'markPrice')
          indexPrice = self.safe_number(premiumIndex, 'indexPrice')
          interestRate = self.safe_number(premiumIndex, 'interestRate')
          estimatedSettlePrice = self.safe_number(premiumIndex, 'estimatedSettlePrice')
          nextFundingRate = self.safe_number(premiumIndex, 'lastFundingRate')
          nextFundingTime = self.safe_integer(premiumIndex, 'nextFundingTime')
          previousFundingTime = nextFundingTime - (8 * 3600000)
          return {
              'info': premiumIndex,
              'symbol': symbol,
              'markPrice': markPrice,
              'indexPrice': indexPrice,
              'interestRate': interestRate,
              'estimatedSettlePrice': estimatedSettlePrice,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'previousFundingRate': None,
              'nextFundingRate': nextFundingRate,
              'previousFundingTimestamp': previousFundingTime,  # subtract 8 hours
              'nextFundingTimestamp': nextFundingTime,
              'previousFundingDatetime': self.iso8601(previousFundingTime),
              'nextFundingDatetime': self.iso8601(nextFundingTime),
          }
  
      def parse_account_positions(self, account):
          positions = self.safe_value(account, 'positions')
          assets = self.safe_value(account, 'assets')
          balances = {}
          for i in range(0, len(assets)):
              entry = assets[i]
              currencyId = self.safe_string(entry, 'asset')
              code = self.safe_currency_code(currencyId)
              crossWalletBalance = self.safe_string(entry, 'crossWalletBalance')
              crossUnPnl = self.safe_string(entry, 'crossUnPnl')
              balances[code] = {
                  'crossMargin': Precise.string_add(crossWalletBalance, crossUnPnl),
                  'crossWalletBalance': crossWalletBalance,
              }
          result = []
          for i in range(0, len(positions)):
              position = positions[i]
              marketId = self.safe_string(position, 'symbol')
              market = self.safe_market(marketId)
              code = market['quote'] if (self.options['defaultType'] == 'future') else market['base']
              # sometimes not all the codes are correctly returned...
              if code in balances:
                  parsed = self.parse_account_position(self.extend(position, {
                      'crossMargin': balances[code]['crossMargin'],
                      'crossWalletBalance': balances[code]['crossWalletBalance'],
                  }), market)
                  result.append(parsed)
          return result
  
      def parse_account_position(self, position, market=None):
          #
          # usdm
          #    {
          #       "symbol": "BTCBUSD",
          #       "initialMargin": "0",
          #       "maintMargin": "0",
          #       "unrealizedProfit": "0.00000000",
          #       "positionInitialMargin": "0",
          #       "openOrderInitialMargin": "0",
          #       "leverage": "20",
          #       "isolated": False,
          #       "entryPrice": "0.0000",
          #       "maxNotional": "100000",
          #       "positionSide": "BOTH",
          #       "positionAmt": "0.000",
          #       "notional": "0",
          #       "isolatedWallet": "0",
          #       "updateTime": "0",
          #       "crossMargin": "100.93634809",
          #     }
          #
          # coinm
          #     {
          #       "symbol": "BTCUSD_210625",
          #       "initialMargin": "0.00024393",
          #       "maintMargin": "0.00002439",
          #       "unrealizedProfit": "-0.00000163",
          #       "positionInitialMargin": "0.00024393",
          #       "openOrderInitialMargin": "0",
          #       "leverage": "10",
          #       "isolated": False,
          #       "positionSide": "BOTH",
          #       "entryPrice": "41021.20000069",
          #       "maxQty": "100",
          #       "notionalValue": "0.00243939",
          #       "isolatedWallet": "0",
          #       "crossMargin": "0.314"
          #       "crossWalletBalance": "34",
          #     }
          #
          marketId = self.safe_string(position, 'symbol')
          market = self.safe_market(marketId, market)
          symbol = market['symbol']
          leverageString = self.safe_string(position, 'leverage')
          leverage = int(leverageString)
          initialMarginString = self.safe_string(position, 'initialMargin')
          initialMargin = self.parse_number(initialMarginString)
          initialMarginPercentageString = Precise.string_div('1', leverageString, 8)
          rational = (1000 % leverage) == 0
          if not rational:
              initialMarginPercentageString = Precise.string_div(Precise.string_add(initialMarginPercentageString, '1e-8'), '1', 8)
          usdm = ('notional' in position)
          maintenanceMarginString = self.safe_string(position, 'maintMargin')
          maintenanceMargin = self.parse_number(maintenanceMarginString)
          entryPriceString = self.safe_string(position, 'entryPrice')
          entryPrice = self.parse_number(entryPriceString)
          notionalString = self.safe_string_2(position, 'notional', 'notionalValue')
          notionalStringAbs = Precise.string_abs(notionalString)
          notionalFloat = float(notionalString)
          notionalFloatAbs = float(notionalStringAbs)
          notional = self.parse_number(Precise.string_abs(notionalString))
          contractsString = self.safe_string(position, 'positionAmt')
          contractsStringAbs = Precise.string_abs(contractsString)
          if contractsString is None:
              entryNotional = Precise.string_mul(Precise.string_mul(leverageString, initialMarginString), entryPriceString)
              contractsString = Precise.string_div(entryNotional, market['contractSize'])
              contractsStringAbs = Precise.string_div(Precise.string_add(contractsString, '0.5'), '1', 0)
          contracts = self.parse_number(contractsStringAbs)
          leverageBrackets = self.safe_value(self.options, 'leverageBrackets', {})
          leverageBracket = self.safe_value(leverageBrackets, symbol, [])
          maintenanceMarginPercentageString = None
          for i in range(0, len(leverageBracket)):
              bracket = leverageBracket[i]
              if notionalFloatAbs < bracket[0]:
                  break
              maintenanceMarginPercentageString = bracket[1]
          maintenanceMarginPercentage = self.parse_number(maintenanceMarginPercentageString)
          unrealizedPnlString = self.safe_string(position, 'unrealizedProfit')
          unrealizedPnl = self.parse_number(unrealizedPnlString)
          timestamp = self.safe_integer(position, 'updateTime')
          if timestamp == 0:
              timestamp = None
          isolated = self.safe_value(position, 'isolated')
          marginType = None
          collateralString = None
          walletBalance = None
          if isolated:
              marginType = 'isolated'
              walletBalance = self.safe_string(position, 'isolatedWallet')
              collateralString = Precise.string_add(walletBalance, unrealizedPnlString)
          else:
              marginType = 'cross'
              walletBalance = self.safe_string(position, 'crossWalletBalance')
              collateralString = self.safe_string(position, 'crossMargin')
          collateral = self.parse_number(collateralString)
          marginRatio = None
          side = None
          percentage = None
          liquidationPriceStringRaw = None
          liquidationPrice = None
          if notionalFloat == 0.0:
              entryPrice = None
          else:
              side = 'short' if (notionalFloat < 0) else 'long'
              marginRatio = self.parse_number(Precise.string_div(Precise.string_add(Precise.string_div(maintenanceMarginString, collateralString), '5e-5'), '1', 4))
              percentage = self.parse_number(Precise.string_mul(Precise.string_div(unrealizedPnlString, initialMarginString, 4), '100'))
              if usdm:
                  # calculate liquidation price
                  #
                  # liquidationPrice = (walletBalance / (contracts * (±1 + mmp))) + (±entryPrice / (±1 + mmp))
                  #
                  # mmp = maintenanceMarginPercentage
                  # where ± is negative for long and positive for short
                  # TODO: calculate liquidation price for coinm contracts
                  onePlusMaintenanceMarginPercentageString = None
                  entryPriceSignString = entryPriceString
                  if side == 'short':
                      onePlusMaintenanceMarginPercentageString = Precise.string_add('1', maintenanceMarginPercentageString)
                  else:
                      onePlusMaintenanceMarginPercentageString = Precise.string_add('-1', maintenanceMarginPercentageString)
                      entryPriceSignString = Precise.string_mul('-1', entryPriceSignString)
                  leftSide = Precise.string_div(walletBalance, Precise.string_mul(contractsStringAbs, onePlusMaintenanceMarginPercentageString))
                  rightSide = Precise.string_div(entryPriceSignString, onePlusMaintenanceMarginPercentageString)
                  liquidationPriceStringRaw = Precise.string_add(leftSide, rightSide)
              else:
                  # calculate liquidation price
                  #
                  # liquidationPrice = (contracts * contractSize(±1 - mmp)) / (±1/entryPrice * contracts * contractSize - walletBalance)
                  #
                  onePlusMaintenanceMarginPercentageString = None
                  entryPriceSignString = entryPriceString
                  if side == 'short':
                      onePlusMaintenanceMarginPercentageString = Precise.string_sub('1', maintenanceMarginPercentageString)
                  else:
                      onePlusMaintenanceMarginPercentageString = Precise.string_sub('-1', maintenanceMarginPercentageString)
                      entryPriceSignString = Precise.string_mul('-1', entryPriceSignString)
                  size = Precise.string_mul(contractsStringAbs, market['contractSize'])
                  leftSide = Precise.string_mul(size, onePlusMaintenanceMarginPercentageString)
                  rightSide = Precise.string_sub(Precise.string_mul(Precise.string_div('1', entryPriceSignString), size), walletBalance)
                  liquidationPriceStringRaw = Precise.string_div(leftSide, rightSide)
              pricePrecision = market['precision']['price']
              pricePrecisionPlusOne = pricePrecision + 1
              pricePrecisionPlusOneString = str(pricePrecisionPlusOne)
              # round half up
              rounder = Precise('5e-' + pricePrecisionPlusOneString)
              rounderString = str(rounder)
              liquidationPriceRoundedString = Precise.string_add(rounderString, liquidationPriceStringRaw)
              truncatedLiquidationPrice = Precise.string_div(liquidationPriceRoundedString, '1', pricePrecision)
              if truncatedLiquidationPrice[0] == '-':
                  # user cannot be liquidated
                  # since he has more collateral than the size of the position
                  truncatedLiquidationPrice = None
              liquidationPrice = self.parse_number(truncatedLiquidationPrice)
          positionSide = self.safe_string(position, 'positionSide')
          hedged = positionSide != 'BOTH'
          return {
              'info': position,
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'initialMargin': initialMargin,
              'initialMarginPercentage': self.parse_number(initialMarginPercentageString),
              'maintenanceMargin': maintenanceMargin,
              'maintenanceMarginPercentage': maintenanceMarginPercentage,
              'entryPrice': entryPrice,
              'notional': notional,
              'leverage': self.parse_number(leverageString),
              'unrealizedPnl': unrealizedPnl,
              'contracts': contracts,
              'contractSize': self.parse_number(market['contractSize']),
              'marginRatio': marginRatio,
              'liquidationPrice': liquidationPrice,
              'markPrice': None,
              'collateral': collateral,
              'marginType': marginType,
              'side': side,
              'hedged': hedged,
              'percentage': percentage,
          }
  
      def parse_position_risk(self, position, market=None):
          #
          # usdm
          #     {
          #       "symbol": "BTCUSDT",
          #       "positionAmt": "0.001",
          #       "entryPrice": "43578.07000",
          #       "markPrice": "43532.30000000",
          #       "unRealizedProfit": "-0.04577000",
          #       "liquidationPrice": "21841.24993976",
          #       "leverage": "2",
          #       "maxNotionalValue": "300000000",
          #       "marginType": "isolated",
          #       "isolatedMargin": "21.77841506",
          #       "isAutoAddMargin": "false",
          #       "positionSide": "BOTH",
          #       "notional": "43.53230000",
          #       "isolatedWallet": "21.82418506",
          #       "updateTime": "1621358023886"
          #     }
          #
          # coinm
          #     {
          #       "symbol": "BTCUSD_PERP",
          #       "positionAmt": "2",
          #       "entryPrice": "37643.10000021",
          #       "markPrice": "38103.05510455",
          #       "unRealizedProfit": "0.00006413",
          #       "liquidationPrice": "25119.97445760",
          #       "leverage": "2",
          #       "maxQty": "1500",
          #       "marginType": "isolated",
          #       "isolatedMargin": "0.00274471",
          #       "isAutoAddMargin": "false",
          #       "positionSide": "BOTH",
          #       "notionalValue": "0.00524892",
          #       "isolatedWallet": "0.00268058"
          #     }
          #
          marketId = self.safe_string(position, 'symbol')
          market = self.safe_market(marketId, market)
          symbol = market['symbol']
          leverageBrackets = self.safe_value(self.options, 'leverageBrackets', {})
          leverageBracket = self.safe_value(leverageBrackets, symbol, [])
          notionalString = self.safe_string_2(position, 'notional', 'notionalValue')
          notionalStringAbs = Precise.string_abs(notionalString)
          notionalFloatAbs = float(notionalStringAbs)
          notionalFloat = float(notionalString)
          maintenanceMarginPercentageString = None
          for i in range(0, len(leverageBracket)):
              bracket = leverageBracket[i]
              if notionalFloatAbs < bracket[0]:
                  break
              maintenanceMarginPercentageString = bracket[1]
          notional = self.parse_number(notionalStringAbs)
          contractsAbs = Precise.string_abs(self.safe_string(position, 'positionAmt'))
          contracts = self.parse_number(contractsAbs)
          unrealizedPnlString = self.safe_string(position, 'unRealizedProfit')
          unrealizedPnl = self.parse_number(unrealizedPnlString)
          leverageString = self.safe_string(position, 'leverage')
          leverage = int(leverageString)
          liquidationPriceString = self.omit_zero(self.safe_string(position, 'liquidationPrice'))
          liquidationPrice = self.parse_number(liquidationPriceString)
          collateralString = None
          marginType = self.safe_string(position, 'marginType')
          side = None
          if notionalFloat > 0:
              side = 'long'
          elif notionalFloat < 0:
              side = 'short'
          entryPriceString = self.safe_string(position, 'entryPrice')
          entryPrice = self.parse_number(entryPriceString)
          if marginType == 'cross':
              # calculate collateral
              if market['linear']:
                  # walletBalance = (liquidationPrice * (±1 + mmp) ± entryPrice) * contracts
                  onePlusMaintenanceMarginPercentageString = None
                  entryPriceSignString = entryPriceString
                  if side == 'short':
                      onePlusMaintenanceMarginPercentageString = Precise.string_add('1', maintenanceMarginPercentageString)
                      entryPriceSignString = Precise.string_mul('-1', entryPriceSignString)
                  else:
                      onePlusMaintenanceMarginPercentageString = Precise.string_add('-1', maintenanceMarginPercentageString)
                  inner = Precise.string_mul(liquidationPriceString, onePlusMaintenanceMarginPercentageString)
                  leftSide = Precise.string_add(inner, entryPriceSignString)
                  collateralString = Precise.string_div(Precise.string_mul(leftSide, contractsAbs), '1', market['precision']['quote'])
              else:
                  # walletBalance = (contracts * contractSize) * (±1/entryPrice - (±1 - mmp) / liquidationPrice)
                  onePlusMaintenanceMarginPercentageString = None
                  entryPriceSignString = entryPriceString
                  if side == 'short':
                      onePlusMaintenanceMarginPercentageString = Precise.string_sub('1', maintenanceMarginPercentageString)
                  else:
                      onePlusMaintenanceMarginPercentageString = Precise.string_sub('-1', maintenanceMarginPercentageString)
                      entryPriceSignString = Precise.string_mul('-1', entryPriceSignString)
                  leftSide = Precise.string_mul(contractsAbs, market['contractSize'])
                  rightSide = Precise.string_sub(Precise.string_div('1', entryPriceSignString), Precise.string_div(onePlusMaintenanceMarginPercentageString, liquidationPriceString))
                  collateralString = Precise.string_div(Precise.string_mul(leftSide, rightSide), '1', market['precision']['base'])
          else:
              collateralString = self.safe_string(position, 'isolatedMargin')
          collateralString = '0' if (collateralString is None) else collateralString
          collateralFloat = float(collateralString)
          collateral = self.parse_number(collateralString)
          markPrice = self.parse_number(self.omit_zero(self.safe_string(position, 'markPrice')))
          timestamp = self.safe_integer(position, 'updateTime')
          if timestamp == 0:
              timestamp = None
          maintenanceMarginPercentage = self.parse_number(maintenanceMarginPercentageString)
          maintenanceMarginString = Precise.string_mul(maintenanceMarginPercentageString, notionalStringAbs)
          maintenanceMargin = self.parse_number(maintenanceMarginString)
          initialMarginPercentageString = Precise.string_div('1', leverageString, 8)
          rational = (1000 % leverage) == 0
          if not rational:
              initialMarginPercentageString = Precise.string_add(initialMarginPercentageString, '1e-8')
          initialMarginString = Precise.string_div(Precise.string_mul(notionalStringAbs, initialMarginPercentageString), '1', 8)
          initialMargin = self.parse_number(initialMarginString)
          marginRatio = None
          percentage = None
          if collateralFloat != 0.0:
              marginRatio = self.parse_number(Precise.string_div(Precise.string_add(Precise.string_div(maintenanceMarginString, collateralString), '5e-5'), '1', 4))
              percentage = self.parse_number(Precise.string_mul(Precise.string_div(unrealizedPnlString, initialMarginString, 4), '100'))
          positionSide = self.safe_string(position, 'positionSide')
          hedged = positionSide != 'BOTH'
          return {
              'info': position,
              'symbol': symbol,
              'contracts': contracts,
              'contractSize': self.parse_number(market['contractSize']),
              'unrealizedPnl': unrealizedPnl,
              'leverage': self.parse_number(leverageString),
              'liquidationPrice': liquidationPrice,
              'collateral': collateral,
              'notional': notional,
              'markPrice': markPrice,
              'entryPrice': entryPrice,
              'timestamp': timestamp,
              'initialMargin': initialMargin,
              'initialMarginPercentage': self.parse_number(initialMarginPercentageString),
              'maintenanceMargin': maintenanceMargin,
              'maintenanceMarginPercentage': maintenanceMarginPercentage,
              'marginRatio': marginRatio,
              'datetime': self.iso8601(timestamp),
              'marginType': marginType,
              'side': side,
              'hedged': hedged,
              'percentage': percentage,
          }
  
      def load_leverage_brackets(self, reload=False, params={}):
          self.load_markets()
          # by default cache the leverage bracket
          # it contains useful stuff like the maintenance margin and initial margin for positions
          leverageBrackets = self.safe_value(self.options, 'leverageBrackets')
          if (leverageBrackets is None) or (reload):
              method = None
              defaultType = self.safe_string(self.options, 'defaultType', 'future')
              type = self.safe_string(params, 'type', defaultType)
              query = self.omit(params, 'type')
              if type == 'future':
                  method = 'fapiPrivateGetLeverageBracket'
              elif type == 'delivery':
                  method = 'dapiPrivateV2GetLeverageBracket'
              else:
                  raise NotSupported(self.id + ' loadLeverageBrackets() supports linear and inverse contracts only')
              response = getattr(self, method)(query)
              self.options['leverageBrackets'] = {}
              for i in range(0, len(response)):
                  entry = response[i]
                  marketId = self.safe_string(entry, 'symbol')
                  symbol = self.safe_symbol(marketId)
                  brackets = self.safe_value(entry, 'brackets')
                  result = []
                  for j in range(0, len(brackets)):
                      bracket = brackets[j]
                      # we use floats here internally on purpose
                      floorValue = self.safe_float_2(bracket, 'notionalFloor', 'qtyFloor')
                      maintenanceMarginPercentage = self.safe_string(bracket, 'maintMarginRatio')
                      result.append([floorValue, maintenanceMarginPercentage])
                  self.options['leverageBrackets'][symbol] = result
          return self.options['leverageBrackets']
  
      def fetch_positions(self, symbols=None, params={}):
          defaultMethod = self.safe_string(self.options, 'fetchPositions', 'positionRisk')
          if defaultMethod == 'positionRisk':
              return self.fetch_positions_risk(symbols, params)
          elif defaultMethod == 'account':
              return self.fetch_account_positions(symbols, params)
          else:
              raise NotSupported(self.id + '.options["fetchPositions"] = "' + defaultMethod + '" is invalid, please choose between "account" and "positionRisk"')
  
      def fetch_account_positions(self, symbols=None, params={}):
          if symbols is not None:
              if not isinstance(symbols, list):
                  raise ArgumentsRequired(self.id + ' fetchPositions requires an array argument for symbols')
          self.load_markets()
          self.load_leverage_brackets()
          method = None
          defaultType = self.safe_string(self.options, 'defaultType', 'future')
          type = self.safe_string(params, 'type', defaultType)
          query = self.omit(params, 'type')
          if type == 'future':
              method = 'fapiPrivateGetAccount'
          elif type == 'delivery':
              method = 'dapiPrivateGetAccount'
          else:
              raise NotSupported(self.id + ' fetchPositions() supports linear and inverse contracts only')
          account = getattr(self, method)(query)
          result = self.parse_account_positions(account)
          return self.filter_by_array(result, 'symbol', symbols, False)
  
      def fetch_positions_risk(self, symbols=None, params={}):
          if symbols is not None:
              if not isinstance(symbols, list):
                  raise ArgumentsRequired(self.id + ' fetchPositions requires an array argument for symbols')
          self.load_markets()
          self.load_leverage_brackets()
          request = {}
          method = None
          defaultType = 'future'
          defaultType = self.safe_string(self.options, 'defaultType', defaultType)
          type = self.safe_string(params, 'type', defaultType)
          params = self.omit(params, 'type')
          if (type == 'future') or (type == 'linear'):
              method = 'fapiPrivateGetPositionRisk'
          elif (type == 'delivery') or (type == 'inverse'):
              method = 'dapiPrivateGetPositionRisk'
          else:
              raise NotSupported(self.id + ' fetchIsolatedPositions() supports linear and inverse contracts only')
          response = getattr(self, method)(self.extend(request, params))
          result = []
          for i in range(0, len(response)):
              parsed = self.parse_position_risk(response[i])
              result.append(parsed)
          return self.filter_by_array(result, 'symbol', symbols, False)
  
      def fetch_funding_history(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          market = None
          method = None
          defaultType = 'future'
          request = {
              'incomeType': 'FUNDING_FEE',  # "TRANSFER"，"WELCOME_BONUS", "REALIZED_PNL"，"FUNDING_FEE", "COMMISSION" and "INSURANCE_CLEAR"
          }
          if symbol is not None:
              market = self.market(symbol)
              request['symbol'] = market['id']
              if market['linear']:
                  defaultType = 'future'
              elif market['inverse']:
                  defaultType = 'delivery'
              else:
                  raise NotSupported(self.id + ' fetchFundingHistory() supports linear and inverse contracts only')
          if since is not None:
              request['startTime'] = since
          if limit is not None:
              request['limit'] = limit
          defaultType = self.safe_string_2(self.options, 'fetchFundingHistory', 'defaultType', defaultType)
          type = self.safe_string(params, 'type', defaultType)
          params = self.omit(params, 'type')
          if (type == 'future') or (type == 'linear'):
              method = 'fapiPrivateGetIncome'
          elif (type == 'delivery') or (type == 'inverse'):
              method = 'dapiPrivateGetIncome'
          else:
              raise NotSupported(self.id + ' fetchFundingHistory() supports linear and inverse contracts only')
          response = getattr(self, method)(self.extend(request, params))
          return self.parse_incomes(response, market, since, limit)
  
      def set_leverage(self, leverage, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
          # WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
          # AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
          if (leverage < 1) or (leverage > 125):
              raise BadRequest(self.id + ' leverage should be between 1 and 125')
          self.load_markets()
          market = self.market(symbol)
          method = None
          if market['linear']:
              method = 'fapiPrivatePostLeverage'
          elif market['inverse']:
              method = 'dapiPrivatePostLeverage'
          else:
              raise NotSupported(self.id + ' setLeverage() supports linear and inverse contracts only')
          request = {
              'symbol': market['id'],
              'leverage': leverage,
          }
          return getattr(self, method)(self.extend(request, params))
  
      def set_margin_mode(self, marginType, symbol=None, params={}):
          #
          # {"code": -4048 , "msg": "Margin type cannot be changed if there exists position."}
          #
          # or
          #
          # {"code": 200, "msg": "success"}
          #
          marginType = marginType.upper()
          if (marginType != 'ISOLATED') and (marginType != 'CROSSED'):
              raise BadRequest(self.id + ' marginType must be either isolated or crossed')
          self.load_markets()
          market = self.market(symbol)
          method = None
          if market['linear']:
              method = 'fapiPrivatePostMarginType'
          elif market['inverse']:
              method = 'dapiPrivatePostMarginType'
          else:
              raise NotSupported(self.id + ' setMarginMode() supports linear and inverse contracts only')
          request = {
              'symbol': market['id'],
              'marginType': marginType,
          }
          return getattr(self, method)(self.extend(request, params))
  
      def set_position_mode(self, hedged, symbol=None, params={}):
          defaultType = self.safe_string(self.options, 'defaultType', 'future')
          type = self.safe_string(params, 'type', defaultType)
          params = self.omit(params, ['type'])
          dualSidePosition = None
          if hedged:
              dualSidePosition = 'true'
          else:
              dualSidePosition = 'false'
          request = {
              'dualSidePosition': dualSidePosition,
          }
          method = None
          if type == 'delivery':
              method = 'dapiPrivatePostPositionSideDual'
          else:
              # default to future
              method = 'fapiPrivatePostPositionSideDual'
          #
          #     {
          #       "code": 200,
          #       "msg": "success"
          #     }
          #
          return getattr(self, method)(self.extend(request, params))
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          if not (api in self.urls['api']):
              raise NotSupported(self.id + ' does not have a testnet/sandbox URL for ' + api + ' endpoints')
          url = self.urls['api'][api]
          url += '/' + path
          if api == 'wapi':
              url += '.html'
          if path == 'historicalTrades':
              if self.apiKey:
                  headers = {
                      'X-MBX-APIKEY': self.apiKey,
                  }
              else:
                  raise AuthenticationError(self.id + ' historicalTrades endpoint requires `apiKey` credential')
          userDataStream = (path == 'userDataStream') or (path == 'listenKey')
          if userDataStream:
              if self.apiKey:
                  # v1 special case for userDataStream
                  headers = {
                      'X-MBX-APIKEY': self.apiKey,
                      'Content-Type': 'application/x-www-form-urlencoded',
                  }
                  if method != 'GET':
                      body = self.urlencode(params)
              else:
                  raise AuthenticationError(self.id + ' userDataStream endpoint requires `apiKey` credential')
          elif (api == 'private') or (api == 'sapi') or (api == 'wapi' and path != 'systemStatus') or (api == 'dapiPrivate') or (api == 'dapiPrivateV2') or (api == 'fapiPrivate') or (api == 'fapiPrivateV2'):
              self.check_required_credentials()
              query = None
              recvWindow = self.safe_integer(self.options, 'recvWindow', 5000)
              if (api == 'sapi') and (path == 'asset/dust'):
                  query = self.urlencode_with_array_repeat(self.extend({
                      'timestamp': self.nonce(),
                      'recvWindow': recvWindow,
                  }, params))
              elif (path == 'batchOrders') or (path.find('sub-account') >= 0):
                  query = self.rawencode(self.extend({
                      'timestamp': self.nonce(),
                      'recvWindow': recvWindow,
                  }, params))
              else:
                  query = self.urlencode(self.extend({
                      'timestamp': self.nonce(),
                      'recvWindow': recvWindow,
                  }, params))
              signature = self.hmac(self.encode(query), self.encode(self.secret))
              query += '&' + 'signature=' + signature
              headers = {
                  'X-MBX-APIKEY': self.apiKey,
              }
              if (method == 'GET') or (method == 'DELETE') or (api == 'wapi'):
                  url += '?' + query
              else:
                  body = query
                  headers['Content-Type'] = 'application/x-www-form-urlencoded'
          else:
              if params:
                  url += '?' + self.urlencode(params)
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if (code == 418) or (code == 429):
              raise DDoSProtection(self.id + ' ' + str(code) + ' ' + reason + ' ' + body)
          # error response in a form: {"code": -1013, "msg": "Invalid quantity."}
          # following block cointains legacy checks against message patterns in "msg" property
          # will switch "code" checks eventually, when we know all of them
          if code >= 400:
              if body.find('Price * QTY is zero or less') >= 0:
                  raise InvalidOrder(self.id + ' order cost = amount * price is zero or less ' + body)
              if body.find('LOT_SIZE') >= 0:
                  raise InvalidOrder(self.id + ' order amount should be evenly divisible by lot size ' + body)
              if body.find('PRICE_FILTER') >= 0:
                  raise InvalidOrder(self.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid float value in general, use self.price_to_precision(symbol, amount) ' + body)
          if response is None:
              return  # fallback to default error handler
          # check success value for wapi endpoints
          # response in format {'msg': 'The coin does not exist.', 'success': True/false}
          success = self.safe_value(response, 'success', True)
          if not success:
              message = self.safe_string(response, 'msg')
              parsedMessage = None
              if message is not None:
                  try:
                      parsedMessage = json.loads(message)
                  except Exception as e:
                      # do nothing
                      parsedMessage = None
                  if parsedMessage is not None:
                      response = parsedMessage
          message = self.safe_string(response, 'msg')
          if message is not None:
              self.throw_exactly_matched_exception(self.exceptions['exact'], message, self.id + ' ' + message)
              self.throw_broadly_matched_exception(self.exceptions['broad'], message, self.id + ' ' + message)
          # checks against error codes
          error = self.safe_string(response, 'code')
          if error is not None:
              # https://github.com/ccxt/ccxt/issues/6501
              # https://github.com/ccxt/ccxt/issues/7742
              if (error == '200') or Precise.string_equals(error, '0'):
                  return
              # a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
              # despite that their message is very confusing, it is raised by Binance
              # on a temporary ban, the API key is valid, but disabled for a while
              if (error == '-2015') and self.options['hasAlreadyAuthenticatedSuccessfully']:
                  raise DDoSProtection(self.id + ' temporary banned: ' + body)
              feedback = self.id + ' ' + body
              self.throw_exactly_matched_exception(self.exceptions['exact'], error, feedback)
              raise ExchangeError(feedback)
          if not success:
              raise ExchangeError(self.id + ' ' + body)
  
      def calculate_rate_limiter_cost(self, api, method, path, params, config={}, context={}):
          if ('noSymbol' in config) and not ('symbol' in params):
              return config['noSymbol']
          elif ('noPoolId' in config) and not ('poolId' in params):
              return config['noPoolId']
          elif ('byLimit' in config) and ('limit' in params):
              limit = params['limit']
              byLimit = config['byLimit']
              for i in range(0, len(byLimit)):
                  entry = byLimit[i]
                  if limit <= entry[0]:
                      return entry[1]
          return self.safe_integer(config, 'cost', 1)
  
      def request(self, path, api='public', method='GET', params={}, headers=None, body=None, config={}, context={}):
          response = self.fetch2(path, api, method, params, headers, body, config, context)
          # a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
          if (api == 'private') or (api == 'wapi'):
              self.options['hasAlreadyAuthenticatedSuccessfully'] = True
          return response
  
      def modify_margin_helper(self, symbol, amount, addOrReduce, params={}):
          # used to modify isolated positions
          defaultType = self.safe_string(self.options, 'defaultType', 'future')
          if defaultType == 'spot':
              defaultType = 'future'
          type = self.safe_string(params, 'type', defaultType)
          if (type == 'margin') or (type == 'spot'):
              raise NotSupported(self.id + ' add / reduce margin only supported with type future or delivery')
          self.load_markets()
          market = self.market(symbol)
          request = {
              'type': addOrReduce,
              'symbol': market['id'],
              'amount': amount,
          }
          method = None
          code = None
          if type == 'future':
              method = 'fapiPrivatePostPositionMargin'
              code = market['quote']
          else:
              method = 'dapiPrivatePostPositionMargin'
              code = market['base']
          response = getattr(self, method)(self.extend(request, params))
          #
          #     {
          #       "code": 200,
          #       "msg": "Successfully modify position margin.",
          #       "amount": 0.001,
          #       "type": 1
          #     }
          #
          rawType = self.safe_integer(response, 'type')
          resultType = 'add' if (rawType == 1) else 'reduce'
          resultAmount = self.safe_number(response, 'amount')
          errorCode = self.safe_string(response, 'code')
          status = 'ok' if (errorCode == '200') else 'failed'
          return {
              'info': response,
              'type': resultType,
              'amount': resultAmount,
              'code': code,
              'symbol': market['symbol'],
              'status': status,
          }
  
      def reduce_margin(self, symbol, amount, params={}):
          return self.modify_margin_helper(symbol, amount, 2, params)
  
      def add_margin(self, symbol, amount, params={}):
          return self.modify_margin_helper(symbol, amount, 1, params)
  