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.async_support.base.exchange import Exchange
  import hashlib
  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 BadResponse
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidAddress
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import DuplicateOrderId
  from ccxt.base.errors import NotSupported
  from ccxt.base.errors import NetworkError
  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 RequestTimeout
  from ccxt.base.precise import Precise
  
  
  class zb(Exchange):
  
      def describe(self):
          return self.deep_extend(super(zb, self).describe(), {
              'id': 'zb',
              'name': 'ZB',
              'countries': ['CN'],
              # previously rateLimit = 100
              # Trading and Margin 10 000 per minute(IP) => 10000 / 60 = 166.66666... per second => rateLimit = 1000/166.66666 = 6
              # Trade and Margin 60 per second(apiKey) => weight = 166.666 / 60 = 2.778(2.7777777...)
              # Kline 1 per second => weight = 166.667
              # v2 Futures API 100 per 2 seconds => 50 per second => weight = 3.334(3.3333333...)
              # for endpoints not mentioned in docs
              # previous rateLimit was 100 translating to 10 requests per second => weight = 166.666 / 10 = 16.667(16.666666...)
              'rateLimit': 6,
              'version': 'v1',
              'certified': True,
              'pro': True,
              'has': {
                  'CORS': None,
                  'spot': True,
                  'margin': True,
                  'swap': True,
                  'future': None,
                  'option': None,
                  'addMargin': True,
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'createMarketOrder': None,
                  'createOrder': True,
                  'createReduceOnlyOrder': False,
                  'createStopLimitOrder': True,
                  'createStopMarketOrder': True,
                  'createStopOrder': True,
                  'fetchBalance': True,
                  'fetchBorrowRate': True,
                  'fetchBorrowRateHistories': False,
                  'fetchBorrowRateHistory': False,
                  'fetchBorrowRates': True,
                  'fetchCanceledOrders': True,
                  'fetchClosedOrders': True,
                  'fetchCurrencies': True,
                  'fetchDepositAddress': True,
                  'fetchDepositAddresses': True,
                  'fetchDeposits': True,
                  'fetchFundingHistory': False,
                  'fetchFundingRate': True,
                  'fetchFundingRateHistory': True,
                  'fetchFundingRates': True,
                  'fetchIndexOHLCV': True,
                  'fetchLedger': True,
                  'fetchLeverage': False,
                  'fetchLeverageTiers': False,
                  'fetchMarketLeverageTiers': False,
                  'fetchMarkets': True,
                  'fetchMarkOHLCV': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchOrders': True,
                  'fetchPosition': True,
                  'fetchPositions': True,
                  'fetchPositionsRisk': False,
                  'fetchPremiumIndexOHLCV': False,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTrades': True,
                  'fetchTradingFee': False,
                  'fetchTradingFees': False,
                  'fetchWithdrawals': True,
                  'reduceMargin': True,
                  'setLeverage': True,
                  'setMarginMode': False,
                  'setPositionMode': False,
                  'transfer': True,
                  'withdraw': True,
              },
              'timeframes': {
                  '1m': '1m',
                  '3m': '3m',
                  '5m': '5m',
                  '15m': '15m',
                  '30m': '30m',
                  '1h': '1h',
                  '2h': '2h',
                  '4h': '4h',
                  '6h': '6h',
                  '12h': '12h',
                  '1d': '1d',
                  '3d': '3d',
                  '5d': '5d',
                  '1w': '1w',
              },
              'hostname': 'zb.com',  # zb.cafe for users in China
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/32859187-cd5214f0-ca5e-11e7-967d-96568e2e2bd1.jpg',
                  'api': {
                      'spot': {
                          'v1': {
                              'public': 'https://api.{hostname}/data',
                              'private': 'https://trade.{hostname}/api',
                          },
                      },
                      'contract': {
                          'v1': {
                              'public': 'https://fapi.{hostname}/api/public',
                          },
                          'v2': {
                              'public': 'https://fapi.{hostname}/Server/api',
                              'private': 'https://fapi.{hostname}/Server/api',
                          },
                      },
                  },
                  'www': 'https://www.zb.com',
                  'doc': 'https://www.zb.com/i/developer',
                  'fees': 'https://www.zb.com/i/rate',
                  'referral': {
                      'url': 'https://www.zbex.club/en/register?ref=4301lera',
                      'discount': 0.16,
                  },
              },
              'api': {
                  'spot': {
                      'v1': {
                          'public': {
                              'get': {
                                  'markets': 16.667,
                                  'ticker': 16.667,
                                  'allTicker': 16.667,
                                  'depth': 16.667,
                                  'trades': 16.667,
                                  'kline': 166.667,  # Kline 1 per second
                                  'getGroupMarkets': 16.667,
                                  'getFeeInfo': 16.667,
                              },
                          },
                          'private': {
                              'get': {
                                  # spot API
                                  'order': 1,  # Trade API
                                  'orderMoreV2': 1,  # Trade API
                                  'cancelOrder': 1,  # Trade API
                                  'cancelAllOrdersAfter': 1,  # Trade API TODO add cancelAllOrders
                                  'getOrder': 1,  # Trade API
                                  'getOrders': 1,  # Trade API
                                  'getOrdersNew': 16.667,
                                  'getOrdersIgnoreTradeType': 1,  # Trade API
                                  'getUnfinishedOrdersIgnoreTradeType': 1,  # Trade API
                                  'getFinishedAndPartialOrders': 1,  # Trade API
                                  'getAccountInfo': 16.667,
                                  'getUserAddress': 16.667,
                                  'getPayinAddress': 16.667,
                                  'getWithdrawAddress': 16.667,
                                  'getWithdrawRecord': 16.667,
                                  'getChargeRecord': 16.667,
                                  'getCnyWithdrawRecord': 16.667,
                                  'getCnyChargeRecord': 16.667,
                                  'withdraw': 16.667,
                                  # sub accounts
                                  'addSubUser': 16.667,
                                  'getSubUserList': 16.667,
                                  'doTransferFunds': 16.667,
                                  'createSubUserKey': 16.667,  # removed on 2021-03-16 according to the update log in the API doc
                                  # leverage API
                                  'getLeverAssetsInfo': 16.667,
                                  'getLeverBills': 16.667,
                                  'transferInLever': 16.667,
                                  'transferOutLever': 16.667,
                                  'loan': 16.667,
                                  'cancelLoan': 16.667,
                                  'getLoans': 16.667,
                                  'getLoanRecords': 16.667,
                                  'borrow': 16.667,
                                  'autoBorrow': 16.667,
                                  'repay': 16.667,
                                  'doAllRepay': 16.667,
                                  'getRepayments': 16.667,
                                  'getFinanceRecords': 16.667,
                                  'changeInvestMark': 16.667,
                                  'changeLoop': 16.667,
                                  # cross API
                                  'getCrossAssets': 16.667,
                                  'getCrossBills': 16.667,
                                  'transferInCross': 16.667,
                                  'transferOutCross': 16.667,
                                  'doCrossLoan': 16.667,
                                  'doCrossRepay': 16.667,
                                  'getCrossRepayRecords': 16.667,
                              },
                          },
                      },
                  },
                  'contract': {
                      'v1': {
                          'public': {
                              'get': {
                                  'depth': 16.667,
                                  'fundingRate': 16.667,
                                  'indexKline': 16.667,
                                  'indexPrice': 16.667,
                                  'kline': 16.667,
                                  'markKline': 16.667,
                                  'markPrice': 16.667,
                                  'ticker': 16.667,
                                  'trade': 16.667,
                              },
                          },
                      },
                      'v2': {
                          'public': {
                              'get': {
                                  'allForceOrders': 3.334,
                                  'config/marketList': 3.334,
                                  'topLongShortAccountRatio': 3.334,
                                  'topLongShortPositionRatio': 3.334,
                                  'fundingRate': 3.334,
                                  'premiumIndex': 3.334,
                              },
                          },
                          'private': {
                              'get': {
                                  'Fund/balance': 3.334,
                                  'Fund/getAccount': 3.334,
                                  'Fund/getBill': 3.334,
                                  'Fund/getBillTypeList': 3.334,
                                  'Fund/marginHistory': 3.334,
                                  'Positions/getPositions': 3.334,
                                  'Positions/getNominalValue': 3.334,
                                  'Positions/marginInfo': 3.334,
                                  'setting/get': 3.334,
                                  'trade/getAllOrders': 3.334,
                                  'trade/getOrder': 3.334,
                                  'trade/getOrderAlgos': 3.334,
                                  'trade/getTradeList': 3.334,
                                  'trade/getUndoneOrders': 3.334,
                                  'trade/tradeHistory': 3.334,
                              },
                              'post': {
                                  'activity/buyTicket': 3.334,
                                  'Fund/transferFund': 3.334,
                                  'Positions/setMarginCoins': 3.334,
                                  'Positions/updateAppendUSDValue': 3.334,
                                  'Positions/updateMargin': 3.334,
                                  'setting/setLeverage': 3.334,
                                  'trade/batchOrder': 3.334,
                                  'trade/batchCancelOrder': 3.334,
                                  'trade/cancelAlgos': 3.334,
                                  'trade/cancelAllOrders': 3.334,
                                  'trade/cancelOrder': 3.334,
                                  'trade/order': 3.334,
                                  'trade/orderAlgo': 3.334,
                                  'trade/updateOrderAlgo': 3.334,
                              },
                          },
                      },
                  },
              },
              'fees': {
                  'funding': {
                      'withdraw': {},
                  },
                  'trading': {
                      'maker': self.parse_number('0.002'),
                      'taker': self.parse_number('0.002'),
                  },
              },
              'commonCurrencies': {
                  'ANG': 'Anagram',
                  'ENT': 'ENTCash',
                  'BCHABC': 'BCHABC',  # conflict with BCH / BCHA
                  'BCHSV': 'BCHSV',  # conflict with BCH / BSV
              },
              'options': {
                  'timeframes': {
                      'spot': {
                          '1m': '1min',
                          '3m': '3min',
                          '5m': '5min',
                          '15m': '15min',
                          '30m': '30min',
                          '1h': '1hour',
                          '2h': '2hour',
                          '4h': '4hour',
                          '6h': '6hour',
                          '12h': '12hour',
                          '1d': '1day',
                          '3d': '3day',
                          '1w': '1week',
                      },
                      'swap': {
                          '1m': '1M',
                          '5m': '5M',
                          '15m': '15M',
                          '30m': '30M',
                          '1h': '1H',
                          '6h': '6H',
                          '1d': '1D',
                          '5d': '5D',
                      },
                  },
              },
              'exceptions': {
                  'ws': {
                      # '1000': ExchangeError,  # The call is successful.
                      '1001': ExchangeError,  # General error prompt
                      '1002': ExchangeError,  # Internal Error
                      '1003': AuthenticationError,  # Fail to verify
                      '1004': AuthenticationError,  # The transaction password is locked
                      '1005': AuthenticationError,  # Wrong transaction password, please check it and re-enter。
                      '1006': PermissionDenied,  # Real-name authentication is pending approval or unapproved
                      '1007': ExchangeError,  # Channel does not exist
                      '1009': OnMaintenance,  # This interface is under maintenance
                      '1010': ExchangeNotAvailable,  # Not available now
                      '1012': PermissionDenied,  # Insufficient permissions
                      '1013': ExchangeError,  # Cannot trade, please contact email: support@zb.cn for support.
                      '1014': ExchangeError,  # Cannot sell during the pre-sale period
                      '2001': InsufficientFunds,  # Insufficient CNY account balance
                      '2002': InsufficientFunds,  # Insufficient BTC account balance
                      '2003': InsufficientFunds,  # Insufficient LTC account balance
                      '2005': InsufficientFunds,  # Insufficient ETH account balance
                      '2006': InsufficientFunds,  # ETCInsufficient account balance
                      '2007': InsufficientFunds,  # BTSInsufficient account balance
                      '2008': InsufficientFunds,  # EOSInsufficient account balance
                      '2009': InsufficientFunds,  # BCCInsufficient account balance
                      '3001': OrderNotFound,  # Order not found or is completed
                      '3002': InvalidOrder,  # Invalid amount
                      '3003': InvalidOrder,  # Invalid quantity
                      '3004': AuthenticationError,  # User does not exist
                      '3005': BadRequest,  # Invalid parameter
                      '3006': PermissionDenied,  # Invalid IP or not consistent with the bound IP
                      '3007': RequestTimeout,  # The request time has expired
                      '3008': ExchangeError,  # Transaction not found
                      '3009': InvalidOrder,  # The price exceeds the limit
                      '3010': PermissionDenied,  # It fails to place an order, due to you have set up to prohibit trading of self market.
                      '3011': InvalidOrder,  # The entrusted price is abnormal, please modify it and place order again
                      '3012': InvalidOrder,  # Duplicate custom customerOrderId
                      '4001': AccountSuspended,  # APIThe interface is locked for one hour
                      '4002': RateLimitExceeded,  # Request too frequently
                  },
                  'exact': {
                      # '1000': 'Successful operation',
                      '10001': ExchangeError,  # Operation failed
                      '10002': PermissionDenied,  # Operation is forbidden
                      '10003': BadResponse,  # Data existed
                      '10004': BadResponse,  # Date not exist
                      '10005': PermissionDenied,  # Forbidden to access the interface
                      '10006': BadRequest,  # Currency invalid or expired
                      '10007': ExchangeError,  # {0}
                      '10008': ExchangeError,  # Operation failed: {0}
                      '10009': ExchangeError,  # URL error
                      '1001': ExchangeError,  # 'General error message',
                      '10010': AuthenticationError,  # API KEY not exist
                      '10011': AuthenticationError,  # API KEY CLOSED
                      '10012': AccountSuspended,  # User API has been frozen, please contact customer service for processing
                      '10013': AuthenticationError,  # API verification failed
                      '10014': AuthenticationError,  # Invalid signature(1001)
                      '10015': AuthenticationError,  # Invalid signature(1002)
                      '10016': AuthenticationError,  # Invalid ip
                      '10017': PermissionDenied,  # Permission denied
                      '10018': AccountSuspended,  # User has been frozen, please contact customer service
                      '10019': RequestTimeout,  # Request time has expired
                      '1002': ExchangeError,  # 'Internal error',
                      '10020': BadRequest,  # {0}Parameter cannot be empty
                      '10021': BadRequest,  # {0}Invalid parameter
                      '10022': BadRequest,  # Request method error
                      '10023': RateLimitExceeded,  # Request frequency is too fast, exceeding the limit allowed by the interface
                      '10024': AuthenticationError,  # Login failed
                      '10025': ExchangeError,  # Non-personal operation
                      '10026': NetworkError,  # Failed to request interface, please try again
                      '10027': RequestTimeout,  # Timed out, please try again later
                      '10028': ExchangeNotAvailable,  # System busy, please try again later
                      '10029': DDoSProtection,  # Frequent operation, please try again later
                      '1003': AuthenticationError,  # 'Verification does not pass',
                      '10030': BadRequest,  # Currency already exist
                      '10031': BadRequest,  # Currency does not exist
                      '10032': BadRequest,  # Market existed
                      '10033': BadRequest,  # Market not exist
                      '10034': BadRequest,  # Currency error
                      '10035': BadRequest,  # Market not open
                      '10036': BadRequest,  # Ineffective market type
                      '10037': ArgumentsRequired,  # User id cannot be empty
                      '10038': BadRequest,  # Market id cannot be empty
                      '10039': BadResponse,  # Failed to get mark price
                      '1004': AuthenticationError,  # 'Funding security password lock',
                      '10040': BadResponse,  # Failed to obtain the opening margin configuration
                      '10041': BadResponse,  # Failed to obtain maintenance margin allocation
                      '10042': ExchangeError,  # Avg. price error
                      '10043': ExchangeError,  # Abnormal acquisition of liquidation price
                      '10044': ExchangeError,  # Unrealized profit and loss acquisition exception
                      '10045': ExchangeError,  # jdbcData source acquisition failed
                      '10046': ExchangeError,  # Invalid position opening direction
                      '10047': ExchangeError,  # The maximum position allowed by the current leverage multiple has been exceeded
                      '10048': ExchangeError,  # The maximum allowable order quantity has been exceeded
                      '10049': NetworkError,  # Failed to get the latest price
                      '1005': AuthenticationError,  # 'Funds security password is incorrect, please confirm and re-enter.',
                      '1006': AuthenticationError,  # 'Real-name certification pending approval or audit does not pass',
                      '1009': ExchangeNotAvailable,  # 'This interface is under maintenance',
                      '1010': ExchangeNotAvailable,  # Not available now
                      '10100': OnMaintenance,  # Sorry! System maintenance, stop operation
                      '1012': PermissionDenied,  # Insufficient permissions
                      '1013': ExchangeError,  # Cannot trade, please contact email: support@zb.cn for support.
                      '1014': ExchangeError,  # Cannot sell during the pre-sale period
                      '11000': ExchangeError,  # Funding change failed
                      '11001': ExchangeError,  # Position change failed
                      '110011': ExchangeError,  # Exceeds the maximum leverage allowed by the position
                      '11002': ExchangeError,  # Funding not exist
                      '11003': ExchangeError,  # Freeze records not exist
                      '11004': InsufficientFunds,  # Insufficient frozen funds
                      '11005': InvalidOrder,  # Insufficient positions
                      '11006': InsufficientFunds,  # Insufficient frozen positions
                      '11007': OrderNotFound,  # Position not exist
                      '11008': ExchangeError,  # The contract have positions, cannot be modified
                      '11009': ExchangeError,  # Failed to query data
                      '110110': ExchangeError,  # Exceed the market's maximum leverage
                      '11012': InsufficientFunds,  # Insufficient margin
                      '11013': ExchangeError,  # Exceeding accuracy limit
                      '11014': ExchangeError,  # Invalid bill type
                      '11015': AuthenticationError,  # Failed to add default account
                      '11016': AuthenticationError,  # Account not exist
                      '11017': ExchangeError,  # Funds are not frozen or unfrozen
                      '11018': InsufficientFunds,  # Insufficient funds
                      '11019': ExchangeError,  # Bill does not exist
                      '11021': InsufficientFunds,  # Inconsistent currency for funds transfer
                      '11023': ExchangeError,  # Same transaction currency
                      '11030': PermissionDenied,  # Position is locked, the operation is prohibited
                      '11031': ExchangeError,  # The number of bill changes is zero
                      '11032': ExchangeError,  # The same request is being processed, please do not submit it repeatedly
                      '11033': ArgumentsRequired,  # Position configuration data is empty
                      '11034': ExchangeError,  # Funding fee is being settled, please do not operate
                      '12000': InvalidOrder,  # Invalid order price
                      '12001': InvalidOrder,  # Invalid order amount
                      '12002': InvalidOrder,  # Invalid order type
                      '12003': InvalidOrder,  # Invalid price accuracy
                      '12004': InvalidOrder,  # Invalid quantity precision
                      '12005': InvalidOrder,  # order value less than the minimum or greater than the maximum
                      '12006': InvalidOrder,  # Customize's order number format is wrong
                      '12007': InvalidOrder,  # Direction error
                      '12008': InvalidOrder,  # Order type error
                      '12009': InvalidOrder,  # Commission type error
                      '12010': InvalidOrder,  # Failed to place the order, the loss of the order placed at self price will exceed margin
                      '12011': InvalidOrder,  # it's not a buz order
                      '12012': OrderNotFound,  # order not exist
                      '12013': InvalidOrder,  # Order user does not match
                      '12014': InvalidOrder,  # Order is still in transaction
                      '12015': InvalidOrder,  # Order preprocessing failed
                      '12016': InvalidOrder,  # Order cannot be canceled
                      '12017': InvalidOrder,  # Transaction Record not exist
                      '12018': InvalidOrder,  # Order failed
                      '12019': ArgumentsRequired,  # self.extend parameter cannot be empty
                      '12020': ExchangeError,  # self.extend Parameter error
                      '12021': InvalidOrder,  # The order price is not within the price limit rules!
                      '12022': InvalidOrder,  # Stop placing an order while the system is calculating the fund fee
                      '12023': OrderNotFound,  # There are no positions to close
                      '12024': InvalidOrder,  # Orders are prohibited, stay tuned!
                      '12025': InvalidOrder,  # Order cancellation is prohibited, so stay tuned!
                      '12026': DuplicateOrderId,  # Order failed， customize order number exists
                      '12027': ExchangeNotAvailable,  # System busy, please try again later
                      '12028': InvalidOrder,  # The market has banned trading
                      '12029': InvalidOrder,  # Forbidden place order, stay tuned
                      '12201': InvalidOrder,  # Delegation strategy does not exist or the status has changed
                      '12202': InvalidOrder,  # Delegation strategy has been changed, cannot be canceled
                      '12203': InvalidOrder,  # Wrong order type
                      '12204': InvalidOrder,  # Invalid trigger price
                      '12205': InvalidOrder,  # The trigger price must be greater than the market’s selling price or lower than the buying price.
                      '12206': InvalidOrder,  # Direction and order type do not match
                      '12207': RateLimitExceeded,  # Submission failed, exceeding the allowed limit
                      '13001': AuthenticationError,  # User not exist
                      '13002': PermissionDenied,  # User did not activate futures
                      # '13003': AuthenticationError,  # User is locked
                      '13003': InvalidOrder,  # Margin gear is not continuous
                      '13004': InvalidOrder,  # The margin quick calculation amount is less than 0
                      '13005': RateLimitExceeded,  # You have exceeded the number of exports that day
                      '13006': ExchangeError,  # No markets are bookmarked
                      '13007': ExchangeError,  # Market not favorited
                      '13008': ExchangeError,  # Not in any market user whitelist
                      '13009': ExchangeError,  # Not in the whitelist of users in self market
                      '14000': ExchangeError,  # {0}not support
                      '14001': AuthenticationError,  # Already logged in, no need to log in multiple times
                      '14002': AuthenticationError,  # Not logged in yet, please log in before subscribing
                      '14003': ExchangeError,  # This is a channel for one-time queries, no need to unsubscribe
                      '14100': ExchangeError,  # Accuracy does not support
                      '14101': RateLimitExceeded,  # Request exceeded frequency limit
                      '14200': ArgumentsRequired,  # id empty
                      '14300': ExchangeError,  # activity not exist
                      '14301': ExchangeError,  # The event has been opened and cannot be admitted
                      '14302': ExchangeError,  # The purchase time has passed and cannot be admitted
                      '14303': ExchangeError,  # Not yet open for the purchase
                      '14305': ExchangeError,  # Cannot enter, the maximum number of returns has been exceeded
                      '14306': ExchangeError,  # Cannot repeat admission
                      '14307': InvalidOrder,  # Unable to cancel, status has been changed
                      '14308': InvalidOrder,  # Unable to cancel, the amount does not match
                      '14309': ExchangeError,  # Activity has not started
                      '14310': NotSupported,  # Activity is over
                      '14311': NotSupported,  # The activity does not support orders placed in self market
                      '14312': ExchangeError,  # You have not participated in self activity
                      '14313': PermissionDenied,  # Sorry! The purchase failed, the maximum number of participants has been reached
                      '14314': ExchangeError,  # Active period id error
                      '2001': InsufficientFunds,  # 'Insufficient CNY Balance',
                      '2002': InsufficientFunds,  # 'Insufficient BTC Balance',
                      '2003': InsufficientFunds,  # 'Insufficient LTC Balance',
                      '2005': InsufficientFunds,  # 'Insufficient ETH Balance',
                      '2006': InsufficientFunds,  # 'Insufficient ETC Balance',
                      '2007': InsufficientFunds,  # 'Insufficient BTS Balance',
                      '2008': InsufficientFunds,  # EOSInsufficient account balance
                      '2009': InsufficientFunds,  # 'Account balance is not enough',
                      '3001': OrderNotFound,  # 'Pending orders not found',
                      '3002': InvalidOrder,  # 'Invalid price',
                      '3003': InvalidOrder,  # 'Invalid amount',
                      '3004': AuthenticationError,  # 'User does not exist',
                      '3005': BadRequest,  # 'Invalid parameter',
                      '3006': AuthenticationError,  # 'Invalid IP or inconsistent with the bound IP',
                      '3007': AuthenticationError,  # 'The request time has expired',
                      '3008': OrderNotFound,  # 'Transaction records not found',
                      '3009': InvalidOrder,  # 'The price exceeds the limit',
                      '3010': PermissionDenied,  # It fails to place an order, due to you have set up to prohibit trading of self market.
                      '3011': InvalidOrder,  # 'The entrusted price is abnormal, please modify it and place order again',
                      '3012': InvalidOrder,  # Duplicate custom customerOrderId
                      '4001': ExchangeNotAvailable,  # 'API interface is locked or not enabled',
                      '4002': RateLimitExceeded,  # 'Request too often',
                      '9999': ExchangeError,  # Unknown error
                  },
                  'broad': {
                      '提币地址有误, 请先添加提币地址。': InvalidAddress,  # {"code":1001,"message":"提币地址有误，请先添加提币地址。"}
                      '资金不足,无法划账': InsufficientFunds,  # {"code":1001,"message":"资金不足,无法划账"}
                      '响应超时': RequestTimeout,  # {"code":1001,"message":"响应超时"}
                  },
              },
          })
  
      async def fetch_markets(self, params={}):
          """
          retrieves data on all markets for zb
          :param dict params: extra parameters specific to the exchange api endpoint
          :returns [dict]: an array of objects representing market data
          """
          markets = await self.spotV1PublicGetMarkets(params)
          #
          #     {
          #         "zb_qc":{
          #             "amountScale":2,
          #             "minAmount":0.01,
          #             "minSize":5,
          #             "priceScale":4,
          #         },
          #     }
          #
          contracts = None
          try:
              # https://github.com/ZBFuture/docs_en/blob/main/API%20V2%20_en.md#7-public-markethttp
              # https://fapi.zb.com/Server/api/v2/config/marketList 502 Bad Gateway
              contracts = await self.contractV2PublicGetConfigMarketList(params)
          except Exception as e:
              contracts = {}
          #
          #     {
          #         BTC_USDT: {
          #             symbol: 'BTC_USDT',
          #             buyerCurrencyId: '6',
          #             contractType: '1',
          #             defaultMarginMode: '1',
          #             marketType: '2',
          #             historyDBName: 'trade_history_readonly.dbc',
          #             defaultLeverage: '20',
          #             id: '100',
          #             canCancelOrder: True,
          #             area: '1',
          #             mixMarginCoinName: 'usdt',
          #             fundingRateRatio: '0.25',
          #             marginCurrencyName: 'usdt',
          #             minTradeMoney: '0.0001',
          #             enableTime: '1638954000000',
          #             maxTradeMoney: '10000000',
          #             canTrade: True,
          #             maxLeverage: '125',
          #             defaultPositionsMode: '2',
          #             onlyWhitelistVisible: False,
          #             riskWarnRatio: '0.8',
          #             marginDecimal: '8',
          #             spot: False,
          #             status: '1',
          #             amountDecimal: '3',
          #             leverage: False,
          #             minAmount: '0.001',
          #             canOrder: True,
          #             duration: '1',
          #             feeDecimal: '8',
          #             sellerCurrencyId: '1',
          #             maxAmount: '1000',
          #             canOpenPosition: True,
          #             isSupportMixMargin: False,
          #             markPriceLimitRate: '0.05',
          #             marginCurrencyId: '6',
          #             stopFundingFee: False,
          #             priceDecimal: '2',
          #             lightenUpFeeRate: '0',
          #             futures: True,
          #             sellerCurrencyName: 'btc',
          #             marketPriceLimitRate: '0.05',
          #             canRebate: True,
          #             marketName: 'BTC_USDT',
          #             depth: [0.01, 0.1, 1],
          #             createTime: '1607590430094',
          #             mixMarginCoinIds: [6],
          #             buyerCurrencyName: 'usdt',
          #             stopService: False
          #         },
          #     }
          #
          contractsData = self.safe_value(contracts, 'data', [])
          contractsById = self.index_by(contractsData, 'marketName')
          dataById = self.deep_extend(contractsById, markets)
          keys = list(dataById.keys())
          result = []
          for i in range(0, len(keys)):
              id = keys[i]
              market = dataById[id]
              baseId, quoteId = id.split('_')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              settleId = self.safe_value(market, 'marginCurrencyName')
              settle = self.safe_currency_code(settleId)
              spot = settle is None
              swap = self.safe_value(market, 'futures', False)
              linear = True if swap else None
              active = True
              symbol = base + '/' + quote
              amountPrecisionString = self.safe_string_2(market, 'amountScale', 'amountDecimal')
              pricePrecisionString = self.safe_string_2(market, 'priceScale', 'priceDecimal')
              if swap:
                  status = self.safe_string(market, 'status')
                  active = (status == '1')
                  symbol = base + '/' + quote + ':' + settle
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'settle': settle,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'settleId': settleId,
                  'type': 'swap' if swap else 'spot',
                  'spot': spot,
                  'margin': False,
                  'swap': swap,
                  'future': False,
                  'option': False,
                  'active': active,
                  'contract': swap,
                  'linear': linear,
                  'inverse': not linear if swap else None,
                  'contractSize': None,
                  'expiry': None,
                  'expiryDatetime': None,
                  'strike': None,
                  'optionType': None,
                  'precision': {
                      'amount': int(amountPrecisionString),
                      'price': int(pricePrecisionString),
                  },
                  'limits': {
                      'leverage': {
                          'min': None,
                          'max': self.safe_number(market, 'maxLeverage'),
                      },
                      'amount': {
                          'min': self.safe_number(market, 'minAmount'),
                          'max': self.safe_number(market, 'maxAmount'),
                      },
                      'price': {
                          'min': None,
                          'max': None,
                      },
                      'cost': {
                          'min': self.safe_number_2(market, 'minSize', 'minTradeMoney'),
                          'max': self.safe_number(market, 'maxTradeMoney'),
                      },
                  },
                  'info': market,
              })
          return result
  
      async def fetch_currencies(self, params={}):
          """
          fetches all available currencies on an exchange
          :param dict params: extra parameters specific to the zb api endpoint
          :returns dict: an associative dictionary of currencies
          """
          response = await self.spotV1PublicGetGetFeeInfo(params)
          #
          #     {
          #         "code":1000,
          #         "message":"success",
          #         "result":{
          #             "USDT":[
          #                 {
          #                     "chainName":"TRC20",
          #                     "canWithdraw":true,
          #                     "fee":1.0,
          #                     "mainChainName":"TRX",
          #                     "canDeposit":true
          #                 },
          #                 {
          #                     "chainName":"OMNI",
          #                     "canWithdraw":true,
          #                     "fee":5.0,
          #                     "mainChainName":"BTC",
          #                     "canDeposit":true
          #                 },
          #                 {
          #                     "chainName":"ERC20",
          #                     "canWithdraw":true,
          #                     "fee":15.0,
          #                     "mainChainName":"ETH",
          #                     "canDeposit":true
          #                 }
          #             ],
          #         }
          #     }
          #
          currencies = self.safe_value(response, 'result', {})
          ids = list(currencies.keys())
          result = {}
          for i in range(0, len(ids)):
              id = ids[i]
              currency = currencies[id]
              code = self.safe_currency_code(id)
              precision = None
              isWithdrawEnabled = True
              isDepositEnabled = True
              fees = {}
              for j in range(0, len(currency)):
                  networkItem = currency[j]
                  network = self.safe_string(networkItem, 'chainName')
                  # name = self.safe_string(networkItem, 'name')
                  withdrawFee = self.safe_number(networkItem, 'fee')
                  depositEnable = self.safe_value(networkItem, 'canDeposit')
                  withdrawEnable = self.safe_value(networkItem, 'canWithdraw')
                  isDepositEnabled = isDepositEnabled or depositEnable
                  isWithdrawEnabled = isWithdrawEnabled or withdrawEnable
                  fees[network] = withdrawFee
              active = (isWithdrawEnabled and isDepositEnabled)
              result[code] = {
                  'id': id,
                  'name': None,
                  'code': code,
                  'precision': precision,
                  'info': currency,
                  'active': active,
                  'deposit': isDepositEnabled,
                  'withdraw': isWithdrawEnabled,
                  'fee': None,
                  'fees': fees,
                  'limits': self.limits,
              }
          return result
  
      def parse_balance(self, response):
          balances = self.safe_value(response['result'], 'coins')
          result = {
              'info': response,
          }
          for i in range(0, len(balances)):
              balance = balances[i]
              #     {       enName: "BTC",
              #               freez: "0.00000000",
              #         unitDecimal:  8,  # always 8
              #              cnName: "BTC",
              #       isCanRecharge:  True,  # TODO: should use self
              #             unitTag: "฿",
              #       isCanWithdraw:  True,  # TODO: should use self
              #           available: "0.00000000",
              #                 key: "btc"         }
              account = self.account()
              currencyId = self.safe_string(balance, 'key')
              code = self.safe_currency_code(currencyId)
              account['free'] = self.safe_string(balance, 'available')
              account['used'] = self.safe_string(balance, 'freez')
              result[code] = account
          return self.safe_balance(result)
  
      def parse_swap_balance(self, response):
          result = {
              'info': response,
          }
          data = self.safe_value(response, 'data', {})
          for i in range(0, len(data)):
              balance = data[i]
              #
              #     {
              #         "userId": "6896693805014120448",
              #         "currencyId": "6",
              #         "currencyName": "usdt",
              #         "amount": "30.56585118",
              #         "freezeAmount": "0",
              #         "contractType": 1,
              #         "id": "6899113714763638819",
              #         "createTime": "1644876888934",
              #         "modifyTime": "1645787446037",
              #         "accountBalance": "30.56585118",
              #         "allMargin": "0",
              #         "allowTransferOutAmount": "30.56585118"
              #     },
              #
              code = self.safe_currency_code(self.safe_string(balance, 'currencyName'))
              account = self.account()
              account['total'] = self.safe_string(balance, 'accountBalance')
              account['free'] = self.safe_string(balance, 'allowTransferOutAmount')
              account['used'] = self.safe_string(balance, 'freezeAmount')
              result[code] = account
          return self.safe_balance(result)
  
      def parse_margin_balance(self, response, marginMode):
          result = {
              'info': response,
          }
          levers = None
          if marginMode == 'isolated':
              message = self.safe_value(response, 'message', {})
              data = self.safe_value(message, 'datas', {})
              levers = self.safe_value(data, 'levers', [])
          else:
              crossResponse = self.safe_value(response, 'result', {})
              levers = self.safe_value(crossResponse, 'list', [])
          for i in range(0, len(levers)):
              balance = levers[i]
              #
              # Isolated Margin
              #
              #     {
              #         "cNetUSD": "0.00",
              #         "repayLeverShow": "-",
              #         "cCanLoanIn": "0.002115400000000",
              #         "fNetCNY": "147.76081161",
              #         "fLoanIn": "0.00",
              #         "repayLevel": 0,
              #         "level": 1,
              #         "netConvertCNY": "147.760811613032",
              #         "cFreeze": "0.00",
              #         "cUnitTag": "BTC",
              #         "version": 1646783178609,
              #         "cAvailableUSD": "0.00",
              #         "cNetCNY": "0.00",
              #         "riskRate": "-",
              #         "fAvailableUSD": "20.49273433",
              #         "fNetUSD": "20.49273432",
              #         "cShowName": "BTC",
              #         "leverMultiple": "5.00",
              #         "couldTransferOutFiat": "20.49273433",
              #         "noticeLine": "1.13",
              #         "fFreeze": "0.00",
              #         "cUnitDecimal": 8,
              #         "fCanLoanIn": "81.970937320000000",
              #         "cAvailable": "0.00",
              #         "repayLock": False,
              #         "status": 1,
              #         "forbidType": 0,
              #         "totalConvertCNY": "147.760811613032",
              #         "cAvailableCNY": "0.00",
              #         "unwindPrice": "0.00",
              #         "fOverdraft": "0.00",
              #         "fShowName": "USDT",
              #         "statusShow": "%E6%AD%A3%E5%B8%B8",
              #         "cOverdraft": "0.00",
              #         "netConvertUSD": "20.49273433",
              #         "cNetBtc": "0.00",
              #         "loanInConvertCNY": "0.00",
              #         "fAvailableCNY": "147.760811613032",
              #         "key": "btcusdt",
              #         "fNetBtc": "0.0005291",
              #         "fUnitDecimal": 8,
              #         "loanInConvertUSD": "0.00",
              #         "showName": "BTC/USDT",
              #         "startLine": "1.25",
              #         "totalConvertUSD": "20.49273433",
              #         "couldTransferOutCoin": "0.00",
              #         "cEnName": "BTC",
              #         "leverMultipleInterest": "3.00",
              #         "fAvailable": "20.49273433",
              #         "fEnName": "USDT",
              #         "forceRepayLine": "1.08",
              #         "cLoanIn": "0.00"
              #     }
              #
              # Cross Margin
              #
              #     [
              #         {
              #             "fundType": 2,
              #             "loanIn": 0,
              #             "amount": 0,
              #             "freeze": 0,
              #             "overdraft": 0,
              #             "key": "BTC",
              #             "canTransferOut": 0
              #         },
              #     ],
              #
              account = self.account()
              if marginMode == 'isolated':
                  code = self.safe_currency_code(self.safe_string(balance, 'fShowName'))
                  account['total'] = self.safe_string(balance, 'fAvailableUSD')  # total amount in USD
                  account['free'] = self.safe_string(balance, 'couldTransferOutFiat')
                  account['used'] = self.safe_string(balance, 'fFreeze')
                  result[code] = account
              else:
                  code = self.safe_currency_code(self.safe_string(balance, 'key'))
                  account['total'] = self.safe_string(balance, 'amount')
                  account['free'] = self.safe_string(balance, 'canTransferOut')
                  account['used'] = self.safe_string(balance, 'freeze')
                  result[code] = account
          return self.safe_balance(result)
  
      async def fetch_balance(self, params={}):
          """
          query for balance and get the amount of funds available for trading or funds locked in orders
          :param dict params: extra parameters specific to the zb api endpoint
          :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
          """
          await self.load_markets()
          marketType, query = self.handle_market_type_and_params('fetchBalance', None, params)
          margin = (marketType == 'margin')
          swap = (marketType == 'swap')
          marginMethod = None
          defaultMargin = 'isolated' if margin else 'cross'
          marginMode = self.safe_string_2(self.options, 'defaultMarginMode', 'marginMode', defaultMargin)
          if marginMode == 'isolated':
              marginMethod = 'spotV1PrivateGetGetLeverAssetsInfo'
          elif marginMode == 'cross':
              marginMethod = 'spotV1PrivateGetGetCrossAssets'
          method = self.get_supported_mapping(marketType, {
              'spot': 'spotV1PrivateGetGetAccountInfo',
              'swap': 'contractV2PrivateGetFundBalance',
              'margin': marginMethod,
          })
          request = {
              # 'futuresAccountType': 1,  # SWAP
              # 'currencyId': currency['id'],  # SWAP
              # 'currencyName': 'usdt',  # SWAP
          }
          if swap:
              request['futuresAccountType'] = 1
          response = await getattr(self, method)(self.extend(request, query))
          #
          # Spot
          #
          #     {
          #         "result": {
          #             "coins": [
          #                 {
          #                     "isCanWithdraw": "true",
          #                     "canLoan": False,
          #                     "fundstype": 51,
          #                     "showName": "ZB",
          #                     "isCanRecharge": "true",
          #                     "cnName": "ZB",
          #                     "enName": "ZB",
          #                     "available": "0",
          #                     "freez": "0",
          #                     "unitTag": "ZB",
          #                     "key": "zb",
          #                     "unitDecimal": 8
          #                 },
          #             ],
          #             "version": 1645856691340,
          #             "base": {
          #                 "auth_google_enabled": True,
          #                 "auth_mobile_enabled": False,
          #                 "trade_password_enabled": True,
          #                 "username": "blank@gmail.com"
          #             }
          #         },
          #         "leverPerm": True,
          #         "otcPerm": False,
          #         "assetPerm": True,
          #         "moneyPerm": True,
          #         "subUserPerm": True,
          #         "entrustPerm": True
          #     }
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "data": [
          #             {
          #                 "userId": "6896693805014120448",
          #                 "currencyId": "6",
          #                 "currencyName": "usdt",
          #                 "amount": "30.56585118",
          #                 "freezeAmount": "0",
          #                 "contractType": 1,
          #                 "id": "6899113714763638819",
          #                 "createTime": "1644876888934",
          #                 "modifyTime": "1645787446037",
          #                 "accountBalance": "30.56585118",
          #                 "allMargin": "0",
          #                 "allowTransferOutAmount": "30.56585118"
          #             },
          #         ],
          #         "desc": "操作成功"
          #     }
          #
          # Isolated Margin
          #
          #     {
          #         "code": 1000,
          #         "message": {
          #             "des": "success",
          #             "isSuc": True,
          #             "datas": {
          #                 "leverPerm": True,
          #                 "levers": [
          #                     {
          #                         "cNetUSD": "0.00",
          #                         "repayLeverShow": "-",
          #                         "cCanLoanIn": "0.002115400000000",
          #                         "fNetCNY": "147.76081161",
          #                         "fLoanIn": "0.00",
          #                         "repayLevel": 0,
          #                         "level": 1,
          #                         "netConvertCNY": "147.760811613032",
          #                         "cFreeze": "0.00",
          #                         "cUnitTag": "BTC",
          #                         "version": 1646783178609,
          #                         "cAvailableUSD": "0.00",
          #                         "cNetCNY": "0.00",
          #                         "riskRate": "-",
          #                         "fAvailableUSD": "20.49273433",
          #                         "fNetUSD": "20.49273432",
          #                         "cShowName": "BTC",
          #                         "leverMultiple": "5.00",
          #                         "couldTransferOutFiat": "20.49273433",
          #                         "noticeLine": "1.13",
          #                         "fFreeze": "0.00",
          #                         "cUnitDecimal": 8,
          #                         "fCanLoanIn": "81.970937320000000",
          #                         "cAvailable": "0.00",
          #                         "repayLock": False,
          #                         "status": 1,
          #                         "forbidType": 0,
          #                         "totalConvertCNY": "147.760811613032",
          #                         "cAvailableCNY": "0.00",
          #                         "unwindPrice": "0.00",
          #                         "fOverdraft": "0.00",
          #                         "fShowName": "USDT",
          #                         "statusShow": "%E6%AD%A3%E5%B8%B8",
          #                         "cOverdraft": "0.00",
          #                         "netConvertUSD": "20.49273433",
          #                         "cNetBtc": "0.00",
          #                         "loanInConvertCNY": "0.00",
          #                         "fAvailableCNY": "147.760811613032",
          #                         "key": "btcusdt",
          #                         "fNetBtc": "0.0005291",
          #                         "fUnitDecimal": 8,
          #                         "loanInConvertUSD": "0.00",
          #                         "showName": "BTC/USDT",
          #                         "startLine": "1.25",
          #                         "totalConvertUSD": "20.49273433",
          #                         "couldTransferOutCoin": "0.00",
          #                         "cEnName": "BTC",
          #                         "leverMultipleInterest": "3.00",
          #                         "fAvailable": "20.49273433",
          #                         "fEnName": "USDT",
          #                         "forceRepayLine": "1.08",
          #                         "cLoanIn": "0.00"
          #                     }
          #                 ]
          #             }
          #         }
          #     }
          #
          # Cross Margin
          #
          #     {
          #         "code": 1000,
          #         "message": "操作成功",
          #         "result": {
          #             "loanIn": 0,
          #             "total": 71.167,
          #             "riskRate": "-",
          #             "list" :[
          #                 {
          #                     "fundType": 2,
          #                     "loanIn": 0,
          #                     "amount": 0,
          #                     "freeze": 0,
          #                     "overdraft": 0,
          #                     "key": "BTC",
          #                     "canTransferOut": 0
          #                 },
          #             ],
          #             "net": 71.167
          #         }
          #     }
          #
          # todo: use self somehow
          # permissions = response['result']['base']
          if swap:
              return self.parse_swap_balance(response)
          elif margin:
              return self.parse_margin_balance(response, marginMode)
          else:
              return self.parse_balance(response)
  
      def parse_deposit_address(self, depositAddress, currency=None):
          #
          # fetchDepositAddress
          #
          #     {
          #         "key": "0x0af7f36b8f09410f3df62c81e5846da673d4d9a9"
          #     }
          #
          # fetchDepositAddresses
          #
          #     {
          #         "blockChain": "btc",
          #         "isUseMemo": False,
          #         "address": "1LL5ati6pXHZnTGzHSA3rWdqi4mGGXudwM",
          #         "canWithdraw": True,
          #         "canDeposit": True
          #     }
          #     {
          #         "blockChain": "bts",
          #         "isUseMemo": True,
          #         "account": "btstest",
          #         "memo": "123",
          #         "canWithdraw": True,
          #         "canDeposit": True
          #     }
          #
          address = self.safe_string_2(depositAddress, 'key', 'address')
          tag = None
          memo = self.safe_string(depositAddress, 'memo')
          if memo is not None:
              tag = memo
          elif address.find('_') >= 0:
              parts = address.split('_')
              address = parts[0]  # WARNING: MAY BE tag_address INSTEAD OF address_tag FOR SOME CURRENCIESnot !
              tag = parts[1]
          self.check_address(address)
          currencyId = self.safe_string(depositAddress, 'blockChain')
          code = self.safe_currency_code(currencyId, currency)
          return {
              'currency': code,
              'address': address,
              'tag': tag,
              'network': None,
              'info': depositAddress,
          }
  
      async def fetch_deposit_addresses(self, codes=None, params={}):
          await self.load_markets()
          response = await self.spotV1PrivateGetGetPayinAddress(params)
          #
          #     {
          #         "code": 1000,
          #         "message": {
          #             "des": "success",
          #             "isSuc": True,
          #             "datas": [
          #                 {
          #                     "blockChain": "btc",
          #                     "isUseMemo": False,
          #                     "address": "1LL5ati6pXHZnTGzHSA3rWdqi4mGGXudwM",
          #                     "canWithdraw": True,
          #                     "canDeposit": True
          #                 },
          #                 {
          #                     "blockChain": "bts",
          #                     "isUseMemo": True,
          #                     "account": "btstest",
          #                     "memo": "123",
          #                     "canWithdraw": True,
          #                     "canDeposit": True
          #                 },
          #             ]
          #         }
          #     }
          #
          message = self.safe_value(response, 'message', {})
          datas = self.safe_value(message, 'datas', [])
          return self.parse_deposit_addresses(datas, codes)
  
      async def fetch_deposit_address(self, code, params={}):
          await self.load_markets()
          currency = self.currency(code)
          request = {
              'currency': currency['id'],
          }
          response = await self.spotV1PrivateGetGetUserAddress(self.extend(request, params))
          #
          #     {
          #         "code": 1000,
          #         "message": {
          #             "des": "success",
          #             "isSuc": True,
          #             "datas": {
          #                 "key": "0x0af7f36b8f09410f3df62c81e5846da673d4d9a9"
          #             }
          #         }
          #     }
          #
          message = self.safe_value(response, 'message', {})
          datas = self.safe_value(message, 'datas', {})
          return self.parse_deposit_address(datas, currency)
  
      async def fetch_order_book(self, symbol, limit=None, params={}):
          """
          fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
          :param str symbol: unified symbol of the market to fetch the order book for
          :param int|None limit: the maximum amount of order book entries to return
          :param dict params: extra parameters specific to the zb api endpoint
          :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/en/latest/manual.html#order-book-structure>` indexed by market symbols
          """
          await self.load_markets()
          market = self.market(symbol)
          request = {
              # 'market': market['id'],  # only applicable to SPOT
              # 'symbol': market['id'],  # only applicable to SWAP
              # 'size': limit,  # 1-50 applicable to SPOT and SWAP
              # 'merge': 5.0,  # float default depth only applicable to SPOT
              # 'scale': 5,  # int accuracy, only applicable to SWAP
          }
          marketIdField = 'symbol' if market['swap'] else 'market'
          request[marketIdField] = market['id']
          method = self.get_supported_mapping(market['type'], {
              'spot': 'spotV1PublicGetDepth',
              'swap': 'contractV1PublicGetDepth',
          })
          if limit is not None:
              request['size'] = limit
          response = await getattr(self, method)(self.extend(request, params))
          #
          # Spot
          #
          #     {
          #         "asks":[
          #             [35000.0,0.2741],
          #             [34949.0,0.0173],
          #             [34900.0,0.5004],
          #         ],
          #         "bids":[
          #             [34119.32,0.0030],
          #             [34107.83,0.1500],
          #             [34104.42,0.1500],
          #         ],
          #         "timestamp":1624536510
          #     }
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "desc": "操作成功",
          #         "data": {
          #             "asks": [
          #                 [43416.6,0.02],
          #                 [43418.25,0.04],
          #                 [43425.82,0.02]
          #             ],
          #             "bids": [
          #                 [43414.61,0.1],
          #                 [43414.18,0.04],
          #                 [43413.03,0.05]
          #             ],
          #             "time": 1645087743071
          #         }
          #     }
          #
          result = None
          timestamp = None
          if market['type'] == 'swap':
              result = self.safe_value(response, 'data')
              timestamp = self.safe_integer(result, 'time')
          else:
              result = response
              timestamp = self.safe_timestamp(response, 'timestamp')
          return self.parse_order_book(result, symbol, timestamp)
  
      async def fetch_tickers(self, symbols=None, params={}):
          """
          fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
          :param [str]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
          :param dict params: extra parameters specific to the zb api endpoint
          :returns dict: an array of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
          """
          await self.load_markets()
          response = await self.spotV1PublicGetAllTicker(params)
          result = {}
          marketsByIdWithoutUnderscore = {}
          marketIds = list(self.markets_by_id.keys())
          for i in range(0, len(marketIds)):
              tickerId = marketIds[i].replace('_', '')
              marketsByIdWithoutUnderscore[tickerId] = self.markets_by_id[marketIds[i]]
          ids = list(response.keys())
          for i in range(0, len(ids)):
              market = self.safe_value(marketsByIdWithoutUnderscore, ids[i])
              if market is not None:
                  symbol = market['symbol']
                  ticker = self.safe_value(response, ids[i])
                  if ticker is not None:
                      result[symbol] = self.parse_ticker(ticker, market)
          return self.filter_by_array(result, 'symbol', symbols)
  
      async def fetch_ticker(self, symbol, params={}):
          """
          fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
          :param str symbol: unified symbol of the market to fetch the ticker for
          :param dict params: extra parameters specific to the zb api endpoint
          :returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
          """
          await self.load_markets()
          market = self.market(symbol)
          request = {
              # 'market': market['id'],  # only applicable to SPOT
              # 'symbol': market['id'],  # only applicable to SWAP
          }
          marketIdField = 'symbol' if market['swap'] else 'market'
          request[marketIdField] = market['id']
          method = self.get_supported_mapping(market['type'], {
              'spot': 'spotV1PublicGetTicker',
              'swap': 'contractV1PublicGetTicker',
          })
          response = await getattr(self, method)(self.extend(request, params))
          #
          # Spot
          #
          #     {
          #         "date":"1624399623587",
          #         "ticker":{
          #             "high":"33298.38",
          #             "vol":"56152.9012",
          #             "last":"32578.55",
          #             "low":"28808.19",
          #             "buy":"32572.68",
          #             "sell":"32615.37",
          #             "turnover":"1764201303.6100",
          #             "open":"31664.85",
          #             "riseRate":"2.89"
          #         }
          #     }
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "desc": "操作成功",
          #         "data": {
          #             "BTC_USDT": [44053.47,44357.77,42911.54,43297.79,53471.264,-1.72,1645093002,302201.255084]
          #         }
          #     }
          #
          ticker = None
          if market['type'] == 'swap':
              ticker = {}
              data = self.safe_value(response, 'data')
              values = self.safe_value(data, market['id'], [])
              for i in range(0, len(values)):
                  ticker['open'] = self.safe_value(values, 0)
                  ticker['high'] = self.safe_value(values, 1)
                  ticker['low'] = self.safe_value(values, 2)
                  ticker['last'] = self.safe_value(values, 3)
                  ticker['vol'] = self.safe_value(values, 4)
                  ticker['riseRate'] = self.safe_value(values, 5)
          else:
              ticker = self.safe_value(response, 'ticker', {})
              ticker['date'] = self.safe_value(response, 'date')
          return self.parse_ticker(ticker, market)
  
      def parse_ticker(self, ticker, market=None):
          #
          # Spot
          #
          #     {
          #         "date":"1624399623587",  # injected from outside
          #         "high":"33298.38",
          #         "vol":"56152.9012",
          #         "last":"32578.55",
          #         "low":"28808.19",
          #         "buy":"32572.68",
          #         "sell":"32615.37",
          #         "turnover":"1764201303.6100",
          #         "open":"31664.85",
          #         "riseRate":"2.89"
          #     }
          #
          # Swap
          #
          #     {
          #         open: 44083.82,
          #         high: 44357.77,
          #         low: 42911.54,
          #         last: 43097.87,
          #         vol: 53451.641,
          #         riseRate: -2.24
          #     }
          #
          timestamp = self.safe_integer(ticker, 'date', self.milliseconds())
          last = self.safe_string(ticker, 'last')
          return self.safe_ticker({
              'symbol': self.safe_symbol(None, market),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_string(ticker, 'high'),
              'low': self.safe_string(ticker, 'low'),
              'bid': self.safe_string(ticker, 'buy'),
              'bidVolume': None,
              'ask': self.safe_string(ticker, 'sell'),
              'askVolume': None,
              'vwap': None,
              'open': self.safe_string(ticker, 'open'),
              'close': last,
              'last': last,
              'previousClose': None,
              'change': None,
              'percentage': None,
              'average': None,
              'baseVolume': self.safe_string(ticker, 'vol'),
              'quoteVolume': None,
              'info': ticker,
          }, market)
  
      def parse_ohlcv(self, ohlcv, market=None):
          if market['swap']:
              ohlcvLength = len(ohlcv)
              if ohlcvLength > 5:
                  return [
                      self.safe_timestamp(ohlcv, 5),
                      self.safe_number(ohlcv, 0),
                      self.safe_number(ohlcv, 1),
                      self.safe_number(ohlcv, 2),
                      self.safe_number(ohlcv, 3),
                      self.safe_number(ohlcv, 4),
                  ]
              else:
                  return [
                      self.safe_timestamp(ohlcv, 4),
                      self.safe_number(ohlcv, 0),
                      self.safe_number(ohlcv, 1),
                      self.safe_number(ohlcv, 2),
                      self.safe_number(ohlcv, 3),
                      None,
                  ]
          else:
              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),
              ]
  
      async def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          """
          fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
          :param str symbol: unified symbol of the market to fetch OHLCV data for
          :param str timeframe: the length of time each candle represents
          :param int|None since: timestamp in ms of the earliest candle to fetch
          :param int|None limit: the maximum amount of candles to fetch
          :param dict params: extra parameters specific to the zb api endpoint
          :returns [[int]]: A list of candles ordered as timestamp, open, high, low, close, volume
          """
          await self.load_markets()
          market = self.market(symbol)
          swap = market['swap']
          spot = market['spot']
          options = self.safe_value(self.options, 'timeframes', {})
          timeframes = self.safe_value(options, market['type'], {})
          timeframeValue = self.safe_string(timeframes, timeframe)
          if timeframeValue is None:
              raise NotSupported(self.id + ' fetchOHLCV() does not support ' + timeframe + ' timeframe for ' + market['type'] + ' markets')
          if limit is None:
              limit = 1000
          request = {
              # 'market': market['id'],  # spot only
              # 'symbol': market['id'],  # swap only
              # 'type': timeframeValue,  # spot only
              # 'period': timeframeValue,  # swap only
              # 'since': since,  # spot only
              # 'size': limit,  # spot and swap
          }
          marketIdField = 'symbol' if swap else 'market'
          request[marketIdField] = market['id']
          periodField = 'period' if swap else 'type'
          request[periodField] = timeframeValue
          price = self.safe_string(params, 'price')
          params = self.omit(params, 'price')
          method = self.get_supported_mapping(market['type'], {
              'spot': 'spotV1PublicGetKline',
              'swap': 'contractV1PublicGetKline',
          })
          if swap:
              if price == 'mark':
                  method = 'contractV1PublicGetMarkKline'
              elif price == 'index':
                  method = 'contractV1PublicGetIndexKline'
          elif spot:
              if since is not None:
                  request['since'] = since
          if limit is not None:
              request['size'] = limit
          response = await getattr(self, method)(self.extend(request, params))
          #
          # Spot
          #
          #     {
          #         "symbol": "BTC",
          #         "data": [
          #             [1645091400000,43183.24,43187.49,43145.92,43182.28,0.9110],
          #             [1645091460000,43182.18,43183.15,43182.06,43183.15,1.4393],
          #             [1645091520000,43182.11,43240.1,43182.11,43240.1,0.3802]
          #         ],
          #         "moneyType": "USDT"
          #     }
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "desc": "操作成功",
          #         "data": [
          #             [41433.44,41433.44,41405.88,41408.75,21.368,1646366460],
          #             [41409.25,41423.74,41408.8,41423.42,9.828,1646366520],
          #             [41423.96,41429.39,41369.98,41370.31,123.104,1646366580]
          #         ]
          #     }
          #
          # Mark
          #
          #     {
          #         "code": 10000,
          #         "desc": "操作成功",
          #         "data": [
          #             [41603.39,41603.39,41591.59,41600.81,1646381760],
          #             [41600.36,41605.75,41587.69,41601.97,1646381820],
          #             [41601.97,41601.97,41562.62,41593.96,1646381880]
          #         ]
          #     }
          #
          # Index
          #
          #     {
          #         "code": 10000,
          #         "desc": "操作成功",
          #         "data": [
          #             [41697.53,41722.29,41689.16,41689.16,1646381640],
          #             [41690.1,41691.73,41611.61,41611.61,1646381700],
          #             [41611.61,41619.49,41594.87,41594.87,1646381760]
          #         ]
          #     }
          #
          data = self.safe_value(response, 'data', [])
          return self.parse_ohlcvs(data, market, timeframe, since, limit)
  
      def parse_trade(self, trade, market=None):
          #
          # Spot
          #
          #     {
          #         "date":1624537391,
          #         "amount":"0.0142",
          #         "price":"33936.42",
          #         "trade_type":"ask",
          #         "type":"sell",
          #         "tid":1718869018
          #     }
          #
          # Swap
          #
          #     {
          #         "amount": "0.002",
          #         "createTime": "1645787446034",
          #         "feeAmount": "-0.05762699",
          #         "feeCurrency": "USDT",
          #         "id": "6902932868050395136",
          #         "maker": False,
          #         "orderId": "6902932868042006528",
          #         "price": "38417.99",
          #         "relizedPnl": "0.30402",
          #         "side": 4,
          #         "userId": "6896693805014120448"
          #     },
          #
          sideField = 'side' if market['swap'] else 'trade_type'
          side = self.safe_string(trade, sideField)
          takerOrMaker = None
          maker = self.safe_value(trade, 'maker')
          if maker is not None:
              takerOrMaker = 'maker' if maker else 'taker'
          if market['spot']:
              side = 'buy' if (side == 'bid') else 'sell'
          else:
              if side == '3':
                  side = 'sell'  # close long
              elif side == '4':
                  side = 'buy'  # close short
              elif side == '1':
                  side = 'buy'  # open long
              elif side == '2':
                  side = 'sell'  # open short
          timestamp = None
          if market['swap']:
              timestamp = self.safe_integer(trade, 'createTime')
          else:
              timestamp = self.safe_timestamp(trade, 'date')
          price = self.safe_string(trade, 'price')
          amount = self.safe_string(trade, 'amount')
          fee = None
          feeCostString = self.safe_string(trade, 'feeAmount')
          if feeCostString is not None:
              feeCurrencyId = self.safe_string(trade, 'feeCurrency')
              fee = {
                  'cost': feeCostString,
                  'currency': self.safe_currency_code(feeCurrencyId),
              }
          market = self.safe_market(None, market)
          return self.safe_trade({
              'info': trade,
              'id': self.safe_string(trade, 'tid'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': market['symbol'],
              'type': None,
              'side': side,
              'order': self.safe_string(trade, 'orderId'),
              'takerOrMaker': takerOrMaker,
              'price': price,
              'amount': amount,
              'cost': None,
              'fee': fee,
          }, market)
  
      async def fetch_trades(self, symbol, since=None, limit=None, params={}):
          """
          get the list of most recent trades for a particular symbol
          :param str symbol: unified symbol of the market to fetch trades for
          :param int|None since: timestamp in ms of the earliest trade to fetch
          :param int|None limit: the maximum amount of trades to fetch
          :param dict params: extra parameters specific to the zb api endpoint
          :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
          """
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchTrades() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          swap = market['swap']
          request = {
              # 'market': market['id'],  # SPOT
              # 'symbol': market['id'],  # SWAP
              # 'side': 1,  # SWAP
              # 'dateRange': 0,  # SWAP
              # 'startTime': since,  # SWAP
              # 'endtime': self.milliseconds(),  # SWAP
              # 'pageNum': 1,  # SWAP
              # 'pageSize': limit,  # SWAP default is 10
          }
          if limit is not None:
              request['pageSize'] = limit
          if since is not None:
              request['startTime'] = since
          marketIdField = 'symbol' if swap else 'market'
          request[marketIdField] = market['id']
          if swap and params['pageNum'] is None:
              request['pageNum'] = 1
          method = self.get_supported_mapping(market['type'], {
              'spot': 'spotV1PublicGetTrades',
              'swap': 'contractV2PrivateGetTradeTradeHistory',
          })
          response = await getattr(self, method)(self.extend(request, params))
          #
          # Spot
          #
          #     [
          #         {"date":1624537391,"amount":"0.0142","price":"33936.42","trade_type":"ask","type":"sell","tid":1718869018},
          #         {"date":1624537391,"amount":"0.0010","price":"33936.42","trade_type":"ask","type":"sell","tid":1718869020},
          #         {"date":1624537391,"amount":"0.0133","price":"33936.42","trade_type":"ask","type":"sell","tid":1718869021},
          #     ]
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "list": [
          #                 {
          #                     "amount": "0.002",
          #                     "createTime": "1645787446034",
          #                     "feeAmount": "-0.05762699",
          #                     "feeCurrency": "USDT",
          #                     "id": "6902932868050395136",
          #                     "maker": False,
          #                     "orderId": "6902932868042006528",
          #                     "price": "38417.99",
          #                     "relizedPnl": "0.30402",
          #                     "side": 4,
          #                     "userId": "6896693805014120448"
          #                 },
          #             ],
          #             "pageNum": 1,
          #             "pageSize": 10
          #         },
          #         "desc": "操作成功"
          #     }
          #
          if swap:
              data = self.safe_value(response, 'data')
              response = self.safe_value(data, 'list')
          return self.parse_trades(response, market, since, limit)
  
      async def create_order(self, symbol, type, side, amount, price=None, params={}):
          """
          create a trade order
          :param str symbol: unified symbol of the market to create an order in
          :param str type: 'market' or 'limit'
          :param str side: 'buy' or 'sell'
          :param float amount: how much of currency you want to trade in units of base currency
          :param float price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
          :param dict params: extra parameters specific to the zb api endpoint
          :returns dict: an `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
          """
          await self.load_markets()
          market = self.market(symbol)
          swap = market['swap']
          spot = market['spot']
          timeInForce = self.safe_string(params, 'timeInForce')
          reduceOnly = self.safe_value(params, 'reduceOnly')
          stop = self.safe_value(params, 'stop')
          stopPrice = self.safe_number_2(params, 'triggerPrice', 'stopPrice')
          if type == 'market':
              raise InvalidOrder(self.id + ' createOrder() on ' + market['type'] + ' markets does not allow market orders')
          method = self.get_supported_mapping(market['type'], {
              'spot': 'spotV1PrivateGetOrder',
              'swap': 'contractV2PrivatePostTradeOrder',
          })
          request = {
              'amount': self.amount_to_precision(symbol, amount),
              # 'symbol': market['id'],
              # 'acctType': 0,  # Spot, Margin 0/1/2 [Spot/Isolated/Cross] Optional, Default to: 0 Spot
              # 'customerOrderId': '1f2g',  # Spot, Margin
              # 'orderType': 1,  # Spot, Margin order type 1/2 [PostOnly/IOC] Optional
              # 'triggerPrice': 30000.0,  # Stop trigger price
              # 'algoPrice': 29000.0,  # Stop order price
              # 'priceType': 1,  # Stop Loss Take Profit, 1: Mark price, 2: Last price
              # 'bizType': 1,  # Stop Loss Take Profit, 1: TP, 2: SL
          }
          if stop or stopPrice:
              method = 'contractV2PrivatePostTradeOrderAlgo'
              orderType = self.safe_integer(params, 'orderType')
              priceType = self.safe_integer(params, 'priceType')
              bizType = self.safe_integer(params, 'bizType')
              algoPrice = self.safe_number(params, 'algoPrice')
              request['symbol'] = market['id']
              if side == 'sell' and reduceOnly:
                  request['side'] = 3  # close long
              elif side == 'buy' and reduceOnly:
                  request['side'] = 4  # close short
              elif side == 'buy':
                  request['side'] = 1  # open long
              elif side == 'sell':
                  request['side'] = 2  # open short
              elif side == 5:
                  request['side'] = 5  # one way position buy
              elif side == 6:
                  request['side'] = 6  # one way position sell
              elif side == 0:
                  request['side'] = 0  # one way position close only
              if type == 'trigger' or orderType == 1:
                  request['orderType'] = 1
              elif type == 'stop loss' or type == 'take profit' or orderType == 2 or priceType or bizType:
                  request['orderType'] = 2
                  request['priceType'] = priceType
                  request['bizType'] = bizType
              request['triggerPrice'] = self.price_to_precision(symbol, stopPrice)
              request['algoPrice'] = self.price_to_precision(symbol, algoPrice)
          else:
              if price:
                  request['price'] = self.price_to_precision(symbol, price)
              if spot:
                  request['tradeType'] = '1' if (side == 'buy') else '0'
                  request['currency'] = market['id']
                  if timeInForce is not None:
                      if timeInForce == 'PO':
                          request['orderType'] = 1
                      elif timeInForce == 'IOC':
                          request['orderType'] = 2
                      else:
                          raise InvalidOrder(self.id + ' createOrder() on ' + market['type'] + ' markets does not allow ' + timeInForce + ' orders')
              elif swap:
                  if side == 'sell' and reduceOnly:
                      request['side'] = 3  # close long
                  elif side == 'buy' and reduceOnly:
                      request['side'] = 4  # close short
                  elif side == 'buy':
                      request['side'] = 1  # open long
                  elif side == 'sell':
                      request['side'] = 2  # open short
                  if type == 'limit':
                      request['action'] = 1
                  elif timeInForce == 'IOC':
                      request['action'] = 3
                  elif timeInForce == 'PO':
                      request['action'] = 4
                  elif timeInForce == 'FOK':
                      request['action'] = 5
                  else:
                      request['action'] = type
                  request['symbol'] = market['id']
                  clientOrderId = self.safe_string(params, 'clientOrderId')  # OPTIONAL '^[a-zA-Z0-9-_]{1,36}$',  # The user-defined order number
                  if clientOrderId is not None:
                      request['clientOrderId'] = clientOrderId
                  # using self.extend as name causes issues in python
                  extendOrderAlgos = self.safe_value(params, 'extend', None)  # OPTIONAL {"orderAlgos":[{"bizType":1,"priceType":1,"triggerPrice":"70000"},{"bizType":2,"priceType":1,"triggerPrice":"40000"}]}
                  if extendOrderAlgos is not None:
                      request['extend'] = extendOrderAlgos
          query = self.omit(params, ['reduceOnly', 'stop', 'stopPrice', 'orderType', 'triggerPrice', 'algoPrice', 'priceType', 'bizType', 'clientOrderId', 'extend'])
          response = await getattr(self, method)(self.extend(request, query))
          #
          # Spot
          #
          #     {
          #         "code": 1000,
          #         "message": "操作成功",
          #         "id": "202202224851151555"
          #     }
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "desc": "操作成功",
          #         "data": {
          #             "orderId": "6901786759944937472",
          #             "orderCode": null
          #         }
          #     }
          #
          # Algo order
          #
          #     {
          #         "code": 10000,
          #         "data": "6919884551305242624",
          #         "desc": "操作成功"
          #     }
          #
          if (swap) and (not stop) and (stopPrice is None):
              response = self.safe_value(response, 'data')
              response['timeInForce'] = timeInForce
              tradeType = self.safe_string(response, 'tradeType')
              if tradeType is None:
                  response['type'] = tradeType
              response['total_amount'] = amount
              response['price'] = price
          return self.parse_order(response, market)
  
      async def cancel_order(self, id, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          swap = market['swap']
          request = {
              # 'currency': self.market_id(symbol),  # only applicable to SPOT
              # 'id': str(id),  # only applicable to SPOT
              # 'symbol': self.market_id(symbol),  # only applicable to SWAP
              # 'orderId': str(id),  # only applicable to SWAP
              # 'clientOrderId': params['clientOrderId'],  # only applicable to SWAP
          }
          marketIdField = 'symbol' if swap else 'currency'
          request[marketIdField] = self.market_id(symbol)
          orderIdField = 'orderId' if swap else 'id'
          request[orderIdField] = str(id)
          method = self.get_supported_mapping(market['type'], {
              'spot': 'spotV1PrivateGetCancelOrder',
              'swap': 'contractV2PrivatePostTradeCancelOrder',
          })
          response = await getattr(self, method)(self.extend(request, params))
          #
          # Spot
          #
          #     {
          #         "code": 1000,
          #         "message": "Success。"
          #     }
          #
          # Swap
          #
          #     {
          #         "code": 10007,
          #         "desc": "orderId与clientOrderId选填1个"
          #     }
          #
          return self.parse_order(response, market)
  
      async def cancel_all_orders(self, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          stop = self.safe_value(params, 'stop')
          if market['spot']:
              raise NotSupported(self.id + ' cancelAllOrders() is not supported on ' + market['type'] + ' markets')
          request = {
              'symbol': market['id'],
              # 'ids': [6904603200733782016, 6819506476072247297],  # STOP
              # 'side': params['side'],  # STOP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
          }
          method = 'contractV2PrivatePostTradeCancelAllOrders'
          if stop:
              method = 'contractV2PrivatePostTradeCancelAlgos'
          query = self.omit(params, 'stop')
          return await getattr(self, method)(self.extend(request, query))
  
      async def fetch_order(self, id, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          reduceOnly = self.safe_value(params, 'reduceOnly')
          stop = self.safe_value(params, 'stop')
          swap = market['swap']
          request = {
              # 'currency': self.market_id(symbol),  # only applicable to SPOT
              # 'id': str(id),  # only applicable to SPOT
              # 'orderId': str(id),  # only applicable to SWAP
              # 'clientOrderId': params['clientOrderId'],  # only applicable to SWAP
              # 'symbol': market['id'],  # STOP and SWAP
              # 'side': params['side'],  # STOP and SWAP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
              # 'orderType': 1,  # STOP, 1: Plan order, 2: SP/SL
              # 'bizType': 1,  # Plan order, 1: TP, 2: SL
              # 'status': 1,  # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
              # 'startTime': since,  # STOP and SWAP
              # 'endTime': params['endTime'],  # STOP and SWAP
              # 'pageNum': 1,  # STOP and SWAP, default 1
              # 'pageSize': limit,  # STOP, default 10
          }
          marketIdField = 'symbol' if swap else 'currency'
          request[marketIdField] = self.market_id(symbol)
          orderIdField = 'orderId' if swap else 'id'
          request[orderIdField] = str(id)
          method = self.get_supported_mapping(market['type'], {
              'spot': 'spotV1PrivateGetGetOrder',
              'swap': 'contractV2PrivateGetTradeGetOrder',
          })
          if stop:
              method = 'contractV2PrivateGetTradeGetOrderAlgos'
              orderType = self.safe_integer(params, 'orderType')
              if orderType is None:
                  raise ArgumentsRequired(self.id + ' fetchOrder() requires an orderType parameter for stop orders')
              side = self.safe_integer(params, 'side')
              bizType = self.safe_integer(params, 'bizType')
              if side == 'sell' and reduceOnly:
                  request['side'] = 3  # close long
              elif side == 'buy' and reduceOnly:
                  request['side'] = 4  # close short
              elif side == 'buy':
                  request['side'] = 1  # open long
              elif side == 'sell':
                  request['side'] = 2  # open short
              elif side == 5:
                  request['side'] = 5  # one way position buy
              elif side == 6:
                  request['side'] = 6  # one way position sell
              elif side == 0:
                  request['side'] = 0  # one way position close only
              if orderType == 1:
                  request['orderType'] = 1
              elif orderType == 2 or bizType:
                  request['orderType'] = 2
                  request['bizType'] = bizType
          query = self.omit(params, ['reduceOnly', 'stop', 'side', 'orderType', 'bizType'])
          response = await getattr(self, method)(self.extend(request, query))
          #
          # Spot
          #
          #     {
          #         'total_amount': 0.01,
          #         'id': '20180910244276459',
          #         'price': 180.0,
          #         'trade_date': 1536576744960,
          #         'status': 2,
          #         'trade_money': '1.96742',
          #         'trade_amount': 0.01,
          #         'type': 0,
          #         'currency': 'eth_usdt'
          #     }
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "action": 1,
          #             "amount": "0.002",
          #             "availableAmount": "0.002",
          #             "availableValue": "60",
          #             "avgPrice": "0",
          #             "canCancel": True,
          #             "cancelStatus": 20,
          #             "createTime": "1646185684379",
          #             "entrustType": 1,
          #             "id": "6904603200733782016",
          #             "leverage": 2,
          #             "margin": "30",
          #             "marketId": "100",
          #             "modifyTime": "1646185684416",
          #             "price": "30000",
          #             "priority": 0,
          #             "showStatus": 1,
          #             "side": 1,
          #             "sourceType": 4,
          #             "status": 12,
          #             "tradeAmount": "0",
          #             "tradeValue": "0",
          #             "type": 1,
          #             "userId": "6896693805014120448",
          #             "value": "60"
          #         },
          #         "desc":"操作成功"
          #     }
          #
          # Algo order
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "list": [
          #                 {
          #                     "action": 1,
          #                     "algoPrice": "30000",
          #                     "amount": "0.003",
          #                     "bizType": 0,
          #                     "canCancel": True,
          #                     "createTime": "1649913941109",
          #                     "errorCode": 0,
          #                     "id": "6920240642849449984",
          #                     "isLong": False,
          #                     "leverage": 10,
          #                     "marketId": "100",
          #                     "modifyTime": "1649913941109",
          #                     "orderType": 1,
          #                     "priceType": 2,
          #                     "side": 5,
          #                     "sourceType": 4,
          #                     "status": 1,
          #                     "submitPrice": "41270.53",
          #                     "symbol": "BTC_USDT",
          #                     "tradedAmount": "0",
          #                     "triggerCondition": "<=",
          #                     "triggerPrice": "31000",
          #                     "triggerTime": "0",
          #                     "userId": "6896693805014120448"
          #                 },
          #             ],
          #             "pageNum": 1,
          #             "pageSize": 10
          #         },
          #         "desc": "操作成功"
          #     }
          #
          if stop:
              data = self.safe_value(response, 'data', {})
              response = self.safe_value(data, 'list', [])
              result = []
              for i in range(0, len(response)):
                  entry = response[i]
                  algoId = self.safe_string(entry, 'id')
                  if id == algoId:
                      result.append(entry)
              response = result[0]
          if swap and not stop:
              response = self.safe_value(response, 'data', {})
          return self.parse_order(response, market)
  
      async def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchOrders() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          reduceOnly = self.safe_value(params, 'reduceOnly')
          stop = self.safe_value(params, 'stop')
          swap = market['swap']
          request = {
              'pageSize': limit,  # default pageSize is 50 for spot, 30 for swap
              # 'currency': market['id'],  # only applicable to SPOT
              # 'pageIndex': 1,  # only applicable to SPOT
              # 'type': params['type'],  # only applicable to SWAP
              # 'dateRange': params['dateRange'],  # only applicable to SWAP
              # 'action': params['action'],  # only applicable to SWAP
              # 'symbol': market['id'],  # STOP and SWAP
              # 'side': params['side'],  # STOP and SWAP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
              # 'orderType': 1,  # STOP, 1: Plan order, 2: SP/SL
              # 'bizType': 1,  # Plan order, 1: TP, 2: SL
              # 'status': 1,  # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
              # 'startTime': since,  # STOP and SWAP
              # 'endTime': params['endTime'],  # STOP and SWAP
              # 'pageNum': 1,  # STOP and SWAP, default 1
              # 'pageSize': limit,  # STOP, default 10
          }
          marketIdField = 'symbol' if market['swap'] else 'currency'
          request[marketIdField] = market['id']
          pageNumField = 'pageNum' if market['swap'] else 'pageIndex'
          request[pageNumField] = 1
          if swap:
              request['startTime'] = since
          method = self.get_supported_mapping(market['type'], {
              'spot': 'spotV1PrivateGetGetOrdersIgnoreTradeType',
              'swap': 'contractV2PrivateGetTradeGetAllOrders',
          })
          # tradeType 交易类型1/0[buy/sell]
          if 'tradeType' in params:
              method = 'spotV1PrivateGetGetOrdersNew'
          if stop:
              method = 'contractV2PrivateGetTradeGetOrderAlgos'
              orderType = self.safe_integer(params, 'orderType')
              if orderType is None:
                  raise ArgumentsRequired(self.id + ' fetchOrders() requires an orderType parameter for stop orders')
              side = self.safe_integer(params, 'side')
              bizType = self.safe_integer(params, 'bizType')
              if side == 'sell' and reduceOnly:
                  request['side'] = 3  # close long
              elif side == 'buy' and reduceOnly:
                  request['side'] = 4  # close short
              elif side == 'buy':
                  request['side'] = 1  # open long
              elif side == 'sell':
                  request['side'] = 2  # open short
              elif side == 5:
                  request['side'] = 5  # one way position buy
              elif side == 6:
                  request['side'] = 6  # one way position sell
              elif side == 0:
                  request['side'] = 0  # one way position close only
              if orderType == 1:
                  request['orderType'] = 1
              elif orderType == 2 or bizType:
                  request['orderType'] = 2
                  request['bizType'] = bizType
          query = self.omit(params, ['reduceOnly', 'stop', 'side', 'orderType', 'bizType'])
          response = None
          try:
              response = await getattr(self, method)(self.extend(request, query))
          except Exception as e:
              if isinstance(e, OrderNotFound):
                  return []
              raise e
          # Spot
          #
          #     [
          #         {
          #             "acctType": 0,
          #             "currency": "btc_usdt",
          #             "fees": 0,
          #             "id": "202202234857482656",
          #             "price": 30000.0,
          #             "status": 3,
          #             "total_amount": 0.0006,
          #             "trade_amount": 0.0000,
          #             "trade_date": 1645610254524,
          #             "trade_money": 0.000000,
          #             "type": 1,
          #             "useZbFee": False,
          #             "webId": 0
          #         }
          #     ]
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "list": [
          #                 {
          #                     "action": 1,
          #                     "amount": "0.004",
          #                     "availableAmount": "0.004",
          #                     "availableValue": "120",
          #                     "avgPrice": "0",
          #                     "canCancel": True,
          #                     "cancelStatus": 20,
          #                     "createTime": "1645609643885",
          #                     "entrustType": 1,
          #                     "id": "6902187111785635850",
          #                     "leverage": 5,
          #                     "margin": "24",
          #                     "marketId": "100",
          #                     "marketName": "BTC_USDT",
          #                     "modifyTime": "1645609643889",
          #                     "price": "30000",
          #                     "showStatus": 1,
          #                     "side": 1,
          #                     "sourceType": 1,
          #                     "status": 12,
          #                     "tradeAmount": "0",
          #                     "tradeValue": "0",
          #                     "type": 1,
          #                     "userId": "6896693805014120448",
          #                     "value": "120"
          #                 },
          #             ],
          #             "pageNum": 1,
          #             "pageSize": 10
          #         },
          #         "desc": "操作成功"
          #     }
          #
          # Algo order
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "list": [
          #                 {
          #                     "action": 1,
          #                     "algoPrice": "30000",
          #                     "amount": "0.003",
          #                     "bizType": 0,
          #                     "canCancel": True,
          #                     "createTime": "1649913941109",
          #                     "errorCode": 0,
          #                     "id": "6920240642849449984",
          #                     "isLong": False,
          #                     "leverage": 10,
          #                     "marketId": "100",
          #                     "modifyTime": "1649913941109",
          #                     "orderType": 1,
          #                     "priceType": 2,
          #                     "side": 5,
          #                     "sourceType": 4,
          #                     "status": 1,
          #                     "submitPrice": "41270.53",
          #                     "symbol": "BTC_USDT",
          #                     "tradedAmount": "0",
          #                     "triggerCondition": "<=",
          #                     "triggerPrice": "31000",
          #                     "triggerTime": "0",
          #                     "userId": "6896693805014120448"
          #                 },
          #             ],
          #             "pageNum": 1,
          #             "pageSize": 10
          #         },
          #         "desc": "操作成功"
          #     }
          #
          if swap:
              data = self.safe_value(response, 'data', {})
              response = self.safe_value(data, 'list', [])
          return self.parse_orders(response, market, since, limit)
  
      async def fetch_canceled_orders(self, symbol=None, since=None, limit=10, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchCanceledOrders() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          reduceOnly = self.safe_value(params, 'reduceOnly')
          stop = self.safe_value(params, 'stop')
          request = {
              'pageSize': limit,  # SPOT and STOP, default pageSize is 10, doesn't work with other values now
              # 'currency': market['id'],  # SPOT
              # 'pageIndex': 1,  # SPOT, default pageIndex is 1
              # 'symbol': market['id'],  # STOP
              # 'side': params['side'],  # STOP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
              # 'orderType': 1,  # STOP, 1: Plan order, 2: SP/SL
              # 'bizType': 1,  # Plan order, 1: TP, 2: SL
              # 'status': 1,  # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
              # 'startTime': since,  # STOP
              # 'endTime': params['endTime'],  # STOP
              # 'pageNum': 1,  # STOP, default 1
          }
          marketIdField = 'currency' if market['spot'] else 'symbol'
          request[marketIdField] = market['id']
          pageNumField = 'pageIndex' if market['spot'] else 'pageNum'
          request[pageNumField] = 1
          method = 'spotV1PrivateGetGetOrdersIgnoreTradeType'
          if stop:
              method = 'contractV2PrivateGetTradeGetOrderAlgos'
              orderType = self.safe_integer(params, 'orderType')
              if orderType is None:
                  raise ArgumentsRequired(self.id + ' fetchCanceledOrders() requires an orderType parameter for stop orders')
              side = self.safe_integer(params, 'side')
              bizType = self.safe_integer(params, 'bizType')
              if side == 'sell' and reduceOnly:
                  request['side'] = 3  # close long
              elif side == 'buy' and reduceOnly:
                  request['side'] = 4  # close short
              elif side == 'buy':
                  request['side'] = 1  # open long
              elif side == 'sell':
                  request['side'] = 2  # open short
              elif side == 5:
                  request['side'] = 5  # one way position buy
              elif side == 6:
                  request['side'] = 6  # one way position sell
              elif side == 0:
                  request['side'] = 0  # one way position close only
              if orderType == 1:
                  request['orderType'] = 1
              elif orderType == 2 or bizType:
                  request['orderType'] = 2
                  request['bizType'] = bizType
              request['status'] = 2
          # tradeType 交易类型1/0[buy/sell]
          if 'tradeType' in params:
              method = 'spotV1PrivateGetGetOrdersNew'
          response = None
          try:
              response = await getattr(self, method)(self.extend(request, params))
          except Exception as e:
              if isinstance(e, OrderNotFound):
                  return []
              raise e
          query = self.omit(params, ['reduceOnly', 'stop', 'side', 'orderType', 'bizType'])
          response = await getattr(self, method)(self.extend(request, query))
          #
          # Spot
          #
          #     [
          #         {
          #             "acctType": 0,
          #             "currency": "btc_usdt",
          #             "fees": 0,
          #             "id": "202202234857482656",
          #             "price": 30000.0,
          #             "status": 1,
          #             "total_amount": 0.0006,
          #             "trade_amount": 0.0000,
          #             "trade_date": 1645610254524,
          #             "trade_money": 0.000000,
          #             "type": 1,
          #             "useZbFee": False,
          #             "webId": 0
          #         }
          #     ]
          #
          # Algo order
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "list": [
          #                 {
          #                     "action": 1,
          #                     "algoPrice": "30000",
          #                     "amount": "0.003",
          #                     "bizType": 0,
          #                     "canCancel": True,
          #                     "createTime": "1649913941109",
          #                     "errorCode": 0,
          #                     "id": "6920240642849449984",
          #                     "isLong": False,
          #                     "leverage": 10,
          #                     "marketId": "100",
          #                     "modifyTime": "1649913941109",
          #                     "orderType": 1,
          #                     "priceType": 2,
          #                     "side": 5,
          #                     "sourceType": 4,
          #                     "status": 2,
          #                     "submitPrice": "41270.53",
          #                     "symbol": "BTC_USDT",
          #                     "tradedAmount": "0",
          #                     "triggerCondition": "<=",
          #                     "triggerPrice": "31000",
          #                     "triggerTime": "0",
          #                     "userId": "6896693805014120448"
          #                 },
          #             ],
          #             "pageNum": 1,
          #             "pageSize": 10
          #         },
          #         "desc": "操作成功"
          #     }
          #
          if stop:
              data = self.safe_value(response, 'data', {})
              response = self.safe_value(data, 'list', [])
          result = []
          if market['type'] == 'spot':
              for i in range(0, len(response)):
                  entry = response[i]
                  status = self.safe_string(entry, 'status')
                  if status == '1':
                      result.append(entry)
              response = result
          return self.parse_orders(response, market, since, limit)
  
      async def fetch_closed_orders(self, symbol=None, since=None, limit=10, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          reduceOnly = self.safe_value(params, 'reduceOnly')
          stop = self.safe_value(params, 'stop')
          request = {
              'pageSize': limit,  # SPOT and STOP, default pageSize is 10, doesn't work with other values now
              # 'currency': market['id'],  # SPOT
              # 'pageIndex': 1,  # SPOT, default pageIndex is 1
              # 'symbol': market['id'],  # STOP
              # 'side': params['side'],  # STOP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
              # 'orderType': 1,  # STOP, 1: Plan order, 2: SP/SL
              # 'bizType': 1,  # Plan order, 1: TP, 2: SL
              # 'status': 1,  # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
              # 'startTime': since,  # STOP
              # 'endTime': params['endTime'],  # STOP
              # 'pageNum': 1,  # STOP, default 1
          }
          marketIdField = 'currency' if market['spot'] else 'symbol'
          request[marketIdField] = market['id']
          pageNumField = 'pageIndex' if market['spot'] else 'pageNum'
          request[pageNumField] = 1
          method = 'spotV1PrivateGetGetFinishedAndPartialOrders'
          if stop:
              method = 'contractV2PrivateGetTradeGetOrderAlgos'
              orderType = self.safe_integer(params, 'orderType')
              if orderType is None:
                  raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires an orderType parameter for stop orders')
              side = self.safe_integer(params, 'side')
              bizType = self.safe_integer(params, 'bizType')
              if side == 'sell' and reduceOnly:
                  request['side'] = 3  # close long
              elif side == 'buy' and reduceOnly:
                  request['side'] = 4  # close short
              elif side == 'buy':
                  request['side'] = 1  # open long
              elif side == 'sell':
                  request['side'] = 2  # open short
              elif side == 5:
                  request['side'] = 5  # one way position buy
              elif side == 6:
                  request['side'] = 6  # one way position sell
              elif side == 0:
                  request['side'] = 0  # one way position close only
              if orderType == 1:
                  request['orderType'] = 1
              elif orderType == 2 or bizType:
                  request['orderType'] = 2
                  request['bizType'] = bizType
              request['status'] = 5
          query = self.omit(params, ['reduceOnly', 'stop', 'side', 'orderType', 'bizType'])
          response = await getattr(self, method)(self.extend(request, query))
          #
          # Spot
          #
          #     [
          #         {
          #             "acctType": 0,
          #             "currency": "btc_usdt",
          #             "fees": 0.00823354,
          #             "id": "202204145086706337",
          #             "price": 41167.7,
          #             "status": 2,
          #             "total_amount": 0.0001,
          #             "trade_amount": 0.0001,
          #             "trade_date": 1649917867370,
          #             "trade_money": 4.116770,
          #             "type": 0,
          #             "useZbFee": False,
          #             "webId": 0
          #         },
          #     ]
          #
          # Algo order
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "list": [
          #                 {
          #                     "action": 1,
          #                     "algoPrice": "30000",
          #                     "amount": "0.003",
          #                     "bizType": 0,
          #                     "canCancel": True,
          #                     "createTime": "1649913941109",
          #                     "errorCode": 0,
          #                     "id": "6920240642849449984",
          #                     "isLong": False,
          #                     "leverage": 10,
          #                     "marketId": "100",
          #                     "modifyTime": "1649913941109",
          #                     "orderType": 1,
          #                     "priceType": 2,
          #                     "side": 5,
          #                     "sourceType": 4,
          #                     "status": 1,
          #                     "submitPrice": "41270.53",
          #                     "symbol": "BTC_USDT",
          #                     "tradedAmount": "0",
          #                     "triggerCondition": "<=",
          #                     "triggerPrice": "31000",
          #                     "triggerTime": "0",
          #                     "userId": "6896693805014120448"
          #                 },
          #             ],
          #             "pageNum": 1,
          #             "pageSize": 10
          #         },
          #         "desc": "操作成功"
          #     }
          #
          if stop:
              data = self.safe_value(response, 'data', {})
              response = self.safe_value(data, 'list', [])
          return self.parse_orders(response, market, since, limit)
  
      async def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          reduceOnly = self.safe_value(params, 'reduceOnly')
          stop = self.safe_value(params, 'stop')
          swap = market['swap']
          request = {
              # 'pageSize': limit,  # default pageSize is 10 for spot, 30 for swap
              # 'currency': market['id'],  # SPOT
              # 'pageIndex': 1,  # SPOT
              # 'symbol': market['id'],  # SWAP and STOP
              # 'pageNum': 1,  # SWAP and STOP, default 1
              # 'type': params['type'],  # swap only
              # 'side': params['side'],  # SWAP and STOP, for stop orders: 1 Open long(buy), 2 Open short(sell), 3 Close long(sell), 4 Close Short(Buy). One-Way Positions: 5 Buy, 6 Sell, 0 Close Only
              # 'action': params['action'],  # SWAP
              # 'orderType': 1,  # STOP, 1: Plan order, 2: SP/SL
              # 'bizType': 1,  # Plan order, 1: TP, 2: SL
              # 'status': 1,  # STOP, 1: untriggered, 2: cancelled, 3:triggered, 4:failed, 5:completed
              # 'startTime': since,  # SWAP and STOP
              # 'endTime': params['endTime'],  # STOP
          }
          if limit is not None:
              request['pageSize'] = limit  # default pageSize is 10 for spot, 30 for swap
          marketIdField = 'symbol' if market['swap'] else 'currency'
          request[marketIdField] = market['id']
          pageNumField = 'pageNum' if market['swap'] else 'pageIndex'
          request[pageNumField] = 1
          if swap and (since is not None):
              request['startTime'] = since
          method = self.get_supported_mapping(market['type'], {
              'spot': 'spotV1PrivateGetGetUnfinishedOrdersIgnoreTradeType',
              'swap': 'contractV2PrivateGetTradeGetUndoneOrders',
          })
          if stop:
              method = 'contractV2PrivateGetTradeGetOrderAlgos'
              orderType = self.safe_integer(params, 'orderType')
              if orderType is None:
                  raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires an orderType parameter for stop orders')
              side = self.safe_integer(params, 'side')
              bizType = self.safe_integer(params, 'bizType')
              if side == 'sell' and reduceOnly:
                  request['side'] = 3  # close long
              elif side == 'buy' and reduceOnly:
                  request['side'] = 4  # close short
              elif side == 'buy':
                  request['side'] = 1  # open long
              elif side == 'sell':
                  request['side'] = 2  # open short
              elif side == 5:
                  request['side'] = 5  # one way position buy
              elif side == 6:
                  request['side'] = 6  # one way position sell
              elif side == 0:
                  request['side'] = 0  # one way position close only
              if orderType == 1:
                  request['orderType'] = 1
              elif orderType == 2 or bizType:
                  request['orderType'] = 2
                  request['bizType'] = bizType
              request['status'] = 1
          query = self.omit(params, ['reduceOnly', 'stop', 'side', 'orderType', 'bizType'])
          # tradeType 交易类型1/0[buy/sell]
          if 'tradeType' in params:
              method = 'spotV1PrivateGetGetOrdersNew'
          response = None
          try:
              response = await getattr(self, method)(self.extend(request, query))
          except Exception as e:
              if isinstance(e, OrderNotFound):
                  return []
              raise e
          #
          # Spot
          #
          #     [
          #         {
          #             "currency": "btc_usdt",
          #             "id": "20150928158614292",
          #             "price": 1560,
          #             "status": 3,
          #             "total_amount": 0.1,
          #             "trade_amount": 0,
          #             "trade_date": 1443410396717,
          #             "trade_money": 0,
          #             "type": 0,
          #             "fees": "0.03",
          #             "useZbFee": True
          #         },
          #     ]
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "list": [
          #                 {
          #                     "action": 1,
          #                     "amount": "0.003",
          #                     "availableAmount": "0.003",
          #                     "availableValue": "90",
          #                     "avgPrice": "0",
          #                     "canCancel": True,
          #                     "cancelStatus": 20,
          #                     "createTime": "1645694610880",
          #                     "entrustType": 1,
          #                     "id": "6902543489192632320",
          #                     "leverage": 5,
          #                     "margin": "18",
          #                     "marketId": "100",
          #                     "modifyTime": "1645694610883",
          #                     "price": "30000",
          #                     "priority": 0,
          #                     "showStatus": 1,
          #                     "side": 1,
          #                     "sourceType": 1,
          #                     "status": 12,
          #                     "tradeAmount": "0",
          #                     "tradeValue": "0",
          #                     "type": 1,
          #                     "userId": "6896693805014120448",
          #                     "value": "90"
          #                 }
          #             ],
          #             "pageNum": 1,
          #             "pageSize": 30
          #         },
          #         "desc": "操作成功"
          #     }
          #
          # Algo order
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "list": [
          #                 {
          #                     "action": 1,
          #                     "algoPrice": "30000",
          #                     "amount": "0.003",
          #                     "bizType": 0,
          #                     "canCancel": True,
          #                     "createTime": "1649913941109",
          #                     "errorCode": 0,
          #                     "id": "6920240642849449984",
          #                     "isLong": False,
          #                     "leverage": 10,
          #                     "marketId": "100",
          #                     "modifyTime": "1649913941109",
          #                     "orderType": 1,
          #                     "priceType": 2,
          #                     "side": 5,
          #                     "sourceType": 4,
          #                     "status": 1,
          #                     "submitPrice": "41270.53",
          #                     "symbol": "BTC_USDT",
          #                     "tradedAmount": "0",
          #                     "triggerCondition": "<=",
          #                     "triggerPrice": "31000",
          #                     "triggerTime": "0",
          #                     "userId": "6896693805014120448"
          #                 },
          #             ],
          #             "pageNum": 1,
          #             "pageSize": 10
          #         },
          #         "desc": "操作成功"
          #     }
          #
          if swap:
              data = self.safe_value(response, 'data', {})
              response = self.safe_value(data, 'list', [])
          return self.parse_orders(response, market, since, limit)
  
      def parse_order(self, order, market=None):
          #
          # Spot fetchOrder, fetchClosedOrders
          #
          #     {
          #         acctType: 0,
          #         currency: 'btc_usdt',
          #         fees: 3.6e-7,
          #         id: '202102282829772463',
          #         price: 45177.5,
          #         status: 2,
          #         total_amount: 0.0002,
          #         trade_amount: 0.0002,
          #         trade_date: 1614515104998,
          #         trade_money: 8.983712,
          #         type: 1,
          #         useZbFee: False
          #     },
          #
          # Swap fetchOrder
          #
          #     {
          #         "action": 1,
          #         "amount": "0.002",
          #         "availableAmount": "0.002",
          #         "availableValue": "60",
          #         "avgPrice": "0",
          #         "canCancel": True,
          #         "cancelStatus": 20,
          #         "createTime": "1646185684379",
          #         "entrustType": 1,
          #         "id": "6904603200733782016",
          #         "leverage": 2,
          #         "margin": "30",
          #         "marketId": "100",
          #         "modifyTime": "1646185684416",
          #         "price": "30000",
          #         "priority": 0,
          #         "showStatus": 1,
          #         "side": 1,
          #         "sourceType": 4,
          #         "status": 12,
          #         "tradeAmount": "0",
          #         "tradeValue": "0",
          #         "type": 1,
          #         "userId": "6896693805014120448",
          #         "value": "60"
          #     },
          #
          # Algo fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders
          #
          #     {
          #         "action": 1,
          #         "algoPrice": "30000",
          #         "amount": "0.003",
          #         "bizType": 0,
          #         "canCancel": True,
          #         "createTime": "1649913941109",
          #         "errorCode": 0,
          #         "id": "6920240642849449984",
          #         "isLong": False,
          #         "leverage": 10,
          #         "marketId": "100",
          #         "modifyTime": "1649913941109",
          #         "orderType": 1,
          #         "priceType": 2,
          #         "side": 5,
          #         "sourceType": 4,
          #         "status": 1,
          #         "submitPrice": "41270.53",
          #         "symbol": "BTC_USDT",
          #         "tradedAmount": "0",
          #         "triggerCondition": "<=",
          #         "triggerPrice": "31000",
          #         "triggerTime": "0",
          #         "userId": "6896693805014120448"
          #     },
          #
          # Spot createOrder
          #
          #     {
          #         code: '1000',
          #         message: '操作成功',
          #         id: '202202224851151555',
          #         type: '1',
          #         total_amount: 0.0002,
          #         price: 30000
          #     }
          #
          # Swap createOrder
          #
          #     {
          #         orderId: '6901786759944937472',
          #         orderCode: null,
          #         timeInForce: 'IOC',
          #         total_amount: 0.0002,
          #         price: 30000
          #     }
          #
          # Algo createOrder
          #
          #     {
          #         "code": 10000,
          #         "data": "6919884551305242624",
          #         "desc": "操作成功"
          #     }
          #
          orderId = self.safe_value(order, 'orderId') if market['swap'] else self.safe_value(order, 'id')
          if orderId is None:
              orderId = self.safe_value(order, 'id')
          side = self.safe_integer_2(order, 'type', 'side')
          if side is None:
              side = None
          else:
              if market['type'] == 'spot':
                  side = 'buy' if (side == 1) else 'sell'
          timestamp = self.safe_integer(order, 'trade_date')
          if timestamp is None:
              timestamp = self.safe_integer(order, 'createTime')
          marketId = self.safe_string(order, 'currency')
          market = self.safe_market(marketId, market, '_')
          price = self.safe_string_2(order, 'price', 'algoPrice')
          filled = self.safe_string(order, 'tradeAmount') if market['swap'] else self.safe_string(order, 'trade_amount')
          amount = self.safe_string(order, 'total_amount')
          if amount is None:
              amount = self.safe_string(order, 'amount')
          cost = self.safe_string(order, 'trade_money')
          status = self.parse_order_status(self.safe_string(order, 'status'), market)
          timeInForce = self.safe_string(order, 'timeInForce')
          postOnly = (timeInForce == 'PO')
          feeCost = self.safe_number(order, 'fees')
          fee = None
          if feeCost is not None:
              feeCurrency = None
              zbFees = self.safe_value(order, 'useZbFee')
              if zbFees is True:
                  feeCurrency = 'ZB'
              else:
                  feeCurrency = market['quote'] if (side == 'sell') else market['base']
              fee = {
                  'cost': feeCost,
                  'currency': feeCurrency,
              }
          return self.safe_order({
              'info': order,
              'id': orderId,
              'clientOrderId': self.safe_string(order, 'userId'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': None,
              'symbol': market['symbol'],
              'type': 'limit',  # market order is not available on ZB
              'timeInForce': timeInForce,
              'postOnly': postOnly,
              'side': side,
              'price': price,
              'stopPrice': self.safe_string(order, 'triggerPrice'),
              'average': self.safe_string(order, 'avgPrice'),
              'cost': cost,
              'amount': amount,
              'filled': filled,
              'remaining': None,
              'status': status,
              'fee': fee,
              'trades': None,
          }, market)
  
      def parse_order_status(self, status, market=None):
          statuses = {}
          if market['type'] == 'spot':
              statuses = {
                  '0': 'open',
                  '1': 'canceled',
                  '2': 'closed',
                  '3': 'open',  # partial
              }
          else:
              statuses = {
                  '1': 'open',
                  '2': 'canceled',
                  '3': 'open',  # stop order triggered
                  '4': 'failed',
                  '5': 'closed',
              }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction_status(self, status):
          statuses = {
              '0': 'pending',  # submitted, pending confirmation
              '1': 'failed',
              '2': 'ok',
              '3': 'canceled',
              '5': 'ok',  # confirmed
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # withdraw
          #
          #     {
          #         "code": 1000,
          #         "message": "success",
          #         "id": "withdrawalId"
          #     }
          #
          # fetchWithdrawals
          #
          #     {
          #         "amount": 0.01,
          #         "fees": 0.001,
          #         "id": 2016042556231,
          #         "manageTime": 1461579340000,
          #         "status": 3,
          #         "submitTime": 1461579288000,
          #         "toAddress": "14fxEPirL9fyfw1i9EF439Pq6gQ5xijUmp",
          #     }
          #
          # fetchDeposits
          #
          #     {
          #         "address": "1FKN1DZqCm8HaTujDioRL2Aezdh7Qj7xxx",
          #         "amount": "1.00000000",
          #         "confirmTimes": 1,
          #         "currency": "BTC",
          #         "description": "Successfully Confirm",
          #         "hash": "7ce842de187c379abafadd64a5fe66c5c61c8a21fb04edff9532234a1dae6xxx",
          #         "id": 558,
          #         "itransfer": 1,
          #         "status": 2,
          #         "submit_time": "2016-12-07 18:51:57",
          #     }
          #
          id = self.safe_string(transaction, 'id')
          txid = self.safe_string(transaction, 'hash')
          amount = self.safe_number(transaction, 'amount')
          timestamp = self.parse8601(self.safe_string(transaction, 'submit_time'))
          timestamp = self.safe_integer(transaction, 'submitTime', timestamp)
          address = self.safe_string_2(transaction, 'toAddress', 'address')
          tag = None
          if address is not None:
              parts = address.split('_')
              address = self.safe_string(parts, 0)
              tag = self.safe_string(parts, 1)
          confirmTimes = self.safe_integer(transaction, 'confirmTimes')
          updated = self.safe_integer(transaction, 'manageTime')
          type = None
          currencyId = self.safe_string(transaction, 'currency')
          code = self.safe_currency_code(currencyId, currency)
          if address is not None:
              type = 'withdrawal' if (confirmTimes is None) else 'deposit'
          status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
          fee = None
          feeCost = self.safe_number(transaction, 'fees')
          if feeCost is not None:
              fee = {
                  'cost': feeCost,
                  'currency': code,
              }
          return {
              'info': transaction,
              'id': id,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'network': None,
              'addressFrom': None,
              'address': address,
              'addressTo': address,
              'tagFrom': None,
              'tag': tag,
              'tagTo': tag,
              'type': type,
              'amount': amount,
              'currency': code,
              'status': status,
              'updated': updated,
              'fee': fee,
          }
  
      async def set_leverage(self, leverage, symbol=None, params={}):
          await self.load_markets()
          if symbol is None:
              raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
          if (leverage < 1) or (leverage > 125):
              raise BadRequest(self.id + ' setLeverage() leverage should be between 1 and 125')
          market = self.market(symbol)
          accountType = None
          if not market['swap']:
              raise BadSymbol(self.id + ' setLeverage() supports swap contracts only')
          else:
              accountType = 1
          request = {
              'symbol': market['id'],
              'leverage': leverage,
              'futuresAccountType': accountType,  # 1: USDT perpetual swaps
          }
          return await self.contractV2PrivatePostSettingSetLeverage(self.extend(request, params))
  
      async def fetch_funding_rate_history(self, symbol=None, since=None, limit=None, params={}):
          """
          fetches historical funding rate prices
          :param str|None symbol: unified symbol of the market to fetch the funding rate history for
          :param int|None since: timestamp in ms of the earliest funding rate to fetch
          :param int|None limit: the maximum amount of `funding rate structures <https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure>` to fetch
          :param dict params: extra parameters specific to the zb api endpoint
          :returns [dict]: a list of `funding rate structures <https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure>`
          """
          await self.load_markets()
          request = {
              # 'symbol': market['id'],
              # 'startTime': since,
              # 'endTime': endTime,  # current time by default
              # 'limit': limit,  # default 100, max 1000
          }
          if symbol is not None:
              market = self.market(symbol)
              symbol = market['symbol']
              request['symbol'] = market['id']
          if since is not None:
              request['startTime'] = since
          till = self.safe_integer(params, 'till')
          endTime = self.safe_string(params, 'endTime')
          params = self.omit(params, ['endTime', 'till'])
          if till is not None:
              request['endTime'] = till
          elif endTime is not None:
              request['endTime'] = endTime
          if limit is not None:
              request['limit'] = limit
          response = await self.contractV2PublicGetFundingRate(self.extend(request, params))
          #
          #     {
          #         "code": 10000,
          #         "data": [
          #             {
          #                 "symbol": "BTC_USDT",
          #                 "fundingRate": "0.0001",
          #                 "fundingTime": "1645171200000"
          #             },
          #         ],
          #         "desc": "操作成功"
          #     }
          #
          data = self.safe_value(response, 'data', [])
          rates = []
          for i in range(0, len(data)):
              entry = data[i]
              marketId = self.safe_string(entry, 'symbol')
              symbol = self.safe_symbol(marketId)
              timestamp = self.safe_string(entry, 'fundingTime')
              rates.append({
                  'info': entry,
                  'symbol': 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)
  
      async def fetch_funding_rate(self, symbol, params={}):
          await self.load_markets()
          market = self.market(symbol)
          if not market['swap']:
              raise BadSymbol(self.id + ' fetchFundingRate() does not supports contracts only')
          request = {
              'symbol': market['id'],
          }
          response = await self.contractV1PublicGetFundingRate(self.extend(request, params))
          #
          #     {
          #         "code": 10000,
          #         "desc": "操作成功",
          #         "data": {
          #             "fundingRate": "0.0001",
          #             "nextCalculateTime": "2022-02-19 00:00:00"
          #         }
          #     }
          #
          data = self.safe_value(response, 'data')
          return self.parse_funding_rate(data, market)
  
      def parse_funding_rate(self, contract, market=None):
          #
          # fetchFundingRate
          #
          #     {
          #         "fundingRate": "0.0001",
          #         "nextCalculateTime": "2022-02-19 00:00:00"
          #     }
          #
          # fetchFundingRates
          #
          #     {
          #         "symbol": "BTC_USDT",
          #         "markPrice": "43254.42",
          #         "indexPrice": "43278.61",
          #         "lastFundingRate": "0.0001",
          #         "nextFundingTime": "1646121600000"
          #     }
          #
          marketId = self.safe_string(contract, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          fundingRate = self.safe_number(contract, 'fundingRate')
          nextFundingDatetime = self.safe_string(contract, 'nextCalculateTime')
          return {
              'info': contract,
              'symbol': symbol,
              'markPrice': self.safe_string(contract, 'markPrice'),
              'indexPrice': self.safe_string(contract, 'indexPrice'),
              'interestRate': None,
              'estimatedSettlePrice': None,
              'timestamp': None,
              'datetime': None,
              'fundingRate': fundingRate,
              'fundingTimestamp': None,
              'fundingDatetime': None,
              'nextFundingRate': None,
              'nextFundingTimestamp': self.parse8601(nextFundingDatetime),
              'nextFundingDatetime': nextFundingDatetime,
              'previousFundingRate': self.safe_string(contract, 'lastFundingRate'),
              'previousFundingTimestamp': None,
              'previousFundingDatetime': None,
          }
  
      async def fetch_funding_rates(self, symbols, params={}):
          await self.load_markets()
          response = await self.contractV2PublicGetPremiumIndex(params)
          #
          #     {
          #         "code": 10000,
          #         "data": [
          #             {
          #                 "symbol": "BTC_USDT",
          #                 "markPrice": "43254.42",
          #                 "indexPrice": "43278.61",
          #                 "lastFundingRate": "0.0001",
          #                 "nextFundingTime": "1646121600000"
          #             },
          #         ],
          #         "desc":"操作成功"
          #     }
          #
          data = self.safe_value(response, 'data', [])
          result = self.parse_funding_rates(data)
          return self.filter_by_array(result, 'symbol', symbols)
  
      async def withdraw(self, code, amount, address, tag=None, params={}):
          tag, params = self.handle_withdraw_tag_and_params(tag, params)
          password = self.safe_string(params, 'safePwd', self.password)
          if password is None:
              raise ArgumentsRequired(self.id + ' withdraw() requires exchange.password or a safePwd parameter')
          fees = self.safe_number(params, 'fees')
          if fees is None:
              raise ArgumentsRequired(self.id + ' withdraw() requires a fees parameter')
          self.check_address(address)
          await self.load_markets()
          currency = self.currency(code)
          if tag is not None:
              address += '_' + tag
          request = {
              'amount': self.currency_to_precision(code, amount),
              'currency': currency['id'],
              'fees': self.currency_to_precision(code, fees),
              # 'itransfer': 0,  # agree for an internal transfer, 0 disagree, 1 agree, the default is to disagree
              'method': 'withdraw',
              'receiveAddr': address,
              'safePwd': password,
          }
          response = await self.spotV1PrivateGetWithdraw(self.extend(request, params))
          #
          #     {
          #         "code": 1000,
          #         "message": "success",
          #         "id": "withdrawalId"
          #     }
          #
          transaction = self.parse_transaction(response, currency)
          return self.extend(transaction, {
              'type': 'withdrawal',
              'address': address,
              'addressTo': address,
              'amount': amount,
          })
  
      async def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'currency': currency['id'],
              # 'pageIndex': 1,
              # 'pageSize': limit,
          }
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['currency'] = currency['id']
          if limit is not None:
              request['pageSize'] = limit
          response = await self.spotV1PrivateGetGetWithdrawRecord(self.extend(request, params))
          #
          #     {
          #         "code": 1000,
          #         "message": {
          #             "des": "success",
          #             "isSuc": True,
          #             "datas": {
          #                 "list": [
          #                     {
          #                         "amount": 0.01,
          #                         "fees": 0.001,
          #                         "id": 2016042556231,
          #                         "manageTime": 1461579340000,
          #                         "status": 3,
          #                         "submitTime": 1461579288000,
          #                         "toAddress": "14fxEPirL9fyfw1i9EF439Pq6gQ5xijUmp",
          #                     },
          #                 ],
          #                 "pageIndex": 1,
          #                 "pageSize": 10,
          #                 "totalCount": 4,
          #                 "totalPage": 1
          #             }
          #         }
          #     }
          #
          message = self.safe_value(response, 'message', {})
          datas = self.safe_value(message, 'datas', {})
          withdrawals = self.safe_value(datas, 'list', [])
          return self.parse_transactions(withdrawals, currency, since, limit)
  
      async def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'currency': currency['id'],
              # 'pageIndex': 1,
              # 'pageSize': limit,
          }
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['currency'] = currency['id']
          if limit is not None:
              request['pageSize'] = limit
          response = await self.spotV1PrivateGetGetChargeRecord(self.extend(request, params))
          #
          #     {
          #         "code": 1000,
          #         "message": {
          #             "des": "success",
          #             "isSuc": True,
          #             "datas": {
          #                 "list": [
          #                     {
          #                         "address": "1FKN1DZqCm8HaTujDioRL2Aezdh7Qj7xxx",
          #                         "amount": "1.00000000",
          #                         "confirmTimes": 1,
          #                         "currency": "BTC",
          #                         "description": "Successfully Confirm",
          #                         "hash": "7ce842de187c379abafadd64a5fe66c5c61c8a21fb04edff9532234a1dae6xxx",
          #                         "id": 558,
          #                         "itransfer": 1,
          #                         "status": 2,
          #                         "submit_time": "2016-12-07 18:51:57",
          #                     },
          #                 ],
          #                 "pageIndex": 1,
          #                 "pageSize": 10,
          #                 "total": 8
          #             }
          #         }
          #     }
          #
          message = self.safe_value(response, 'message', {})
          datas = self.safe_value(message, 'datas', {})
          deposits = self.safe_value(datas, 'list', [])
          return self.parse_transactions(deposits, currency, since, limit)
  
      async def fetch_position(self, symbol, params={}):
          await self.load_markets()
          market = None
          if symbol is not None:
              market = self.market(symbol)
          request = {
              'futuresAccountType': 1,  # 1: USDT-M Perpetual Futures
              # 'symbol': market['id'],
              # 'marketId': market['id'],
              # 'side': params['side'],
          }
          response = await self.contractV2PrivateGetPositionsGetPositions(self.extend(request, params))
          #
          #     {
          #         "code": 10000,
          #         "data": [
          #             {
          #                 "amount": "0.002",
          #                 "appendAmount": "0",
          #                 "autoLightenRatio": "0",
          #                 "avgPrice": "38570",
          #                 "bankruptcyPrice": "46288.41",
          #                 "contractType": 1,
          #                 "createTime": "1645784751867",
          #                 "freezeAmount": "0",
          #                 "freezeList": [
          #                     {
          #                         "amount": "15.436832",
          #                         "currencyId": "6",
          #                         "currencyName": "usdt",
          #                         "modifyTime": "1645784751867"
          #                     }
          #                 ],
          #                 "id": "6902921567894972486",
          #                 "lastAppendAmount": "0",
          #                 "leverage": 5,
          #                 "liquidateLevel": 1,
          #                 "liquidatePrice": "46104",
          #                 "maintainMargin": "0.30912384",
          #                 "margin": "15.436832",
          #                 "marginAppendCount": 0,
          #                 "marginBalance": "15.295872",
          #                 "marginMode": 1,
          #                 "marginRate": "0.020209",
          #                 "marketId": "100",
          #                 "marketName": "BTC_USDT",
          #                 "modifyTime": "1645784751867",
          #                 "nominalValue": "77.14736",
          #                 "originAppendAmount": "0",
          #                 "originId": "6902921567894972591",
          #                 "refreshType": "Timer",
          #                 "returnRate": "-0.0091",
          #                 "side": 0,
          #                 "status": 1,
          #                 "unrealizedPnl": "-0.14096",
          #                 "userId": "6896693805014120448"
          #             }
          #         ],
          #         "desc": "操作成功"
          #     }
          #
          data = self.safe_value(response, 'data', [])
          firstPosition = self.safe_value(data, 0)
          return self.parse_position(firstPosition, market)
  
      async def fetch_positions(self, symbols=None, params={}):
          await self.load_markets()
          request = {
              'futuresAccountType': 1,  # 1: USDT-M Perpetual Futures
              # 'symbol': market['id'],
              # 'marketId': market['id'],
              # 'side': params['side'],
          }
          response = await self.contractV2PrivateGetPositionsGetPositions(self.extend(request, params))
          #
          #     {
          #         "code": 10000,
          #         "data": [
          #             {
          #                 "amount": "0.002",
          #                 "appendAmount": "0",
          #                 "autoLightenRatio": "0",
          #                 "avgPrice": "38570",
          #                 "bankruptcyPrice": "46288.41",
          #                 "contractType": 1,
          #                 "createTime": "1645784751867",
          #                 "freezeAmount": "0",
          #                 "freezeList": [
          #                     {
          #                         "amount": "15.436832",
          #                         "currencyId": "6",
          #                         "currencyName": "usdt",
          #                         "modifyTime": "1645784751867"
          #                     }
          #                 ],
          #                 "id": "6902921567894972486",
          #                 "lastAppendAmount": "0",
          #                 "leverage": 5,
          #                 "liquidateLevel": 1,
          #                 "liquidatePrice": "46104",
          #                 "maintainMargin": "0.30912384",
          #                 "margin": "15.436832",
          #                 "marginAppendCount": 0,
          #                 "marginBalance": "15.295872",
          #                 "marginMode": 1,
          #                 "marginRate": "0.020209",
          #                 "marketId": "100",
          #                 "marketName": "BTC_USDT",
          #                 "modifyTime": "1645784751867",
          #                 "nominalValue": "77.14736",
          #                 "originAppendAmount": "0",
          #                 "originId": "6902921567894972591",
          #                 "refreshType": "Timer",
          #                 "returnRate": "-0.0091",
          #                 "side": 0,
          #                 "status": 1,
          #                 "unrealizedPnl": "-0.14096",
          #                 "userId": "6896693805014120448"
          #             },
          #         ],
          #         "desc": "操作成功"
          #     }
          #
          data = self.safe_value(response, 'data', [])
          return self.parse_positions(data, symbols)
  
      def parse_position(self, position, market=None):
          #
          #     {
          #         "amount": "0.002",
          #         "appendAmount": "0",
          #         "autoLightenRatio": "0",
          #         "avgPrice": "38570",
          #         "bankruptcyPrice": "46288.41",
          #         "contractType": 1,
          #         "createTime": "1645784751867",
          #         "freezeAmount": "0",
          #         "freezeList": [
          #             {
          #                 "amount": "15.436832",
          #                 "currencyId": "6",
          #                 "currencyName": "usdt",
          #                 "modifyTime": "1645784751867"
          #             }
          #         ],
          #         "id": "6902921567894972486",
          #         "lastAppendAmount": "0",
          #         "leverage": 5,
          #         "liquidateLevel": 1,
          #         "liquidatePrice": "46104",
          #         "maintainMargin": "0.30912384",
          #         "margin": "15.436832",
          #         "marginAppendCount": 0,
          #         "marginBalance": "15.295872",
          #         "marginMode": 1,
          #         "marginRate": "0.020209",
          #         "marketId": "100",
          #         "marketName": "BTC_USDT",
          #         "modifyTime": "1645784751867",
          #         "nominalValue": "77.14736",
          #         "originAppendAmount": "0",
          #         "originId": "6902921567894972591",
          #         "refreshType": "Timer",
          #         "returnRate": "-0.0091",
          #         "side": 0,
          #         "status": 1,
          #         "unrealizedPnl": "-0.14096",
          #         "userId": "6896693805014120448"
          #     }
          #
          marketId = self.safe_string(position, 'marketName')
          market = self.safe_market(marketId, market)
          symbol = market['symbol']
          contracts = self.safe_string(position, 'amount')
          entryPrice = self.safe_number(position, 'avgPrice')
          initialMargin = self.safe_string(position, 'margin')
          rawSide = self.safe_string(position, 'side')
          side = 'long' if (rawSide == '1') else 'short'
          openType = self.safe_string(position, 'marginMode')
          marginMode = 'isolated' if (openType == '1') else 'cross'
          leverage = self.safe_string(position, 'leverage')
          liquidationPrice = self.safe_number(position, 'liquidatePrice')
          unrealizedProfit = self.safe_number(position, 'unrealizedPnl')
          maintenanceMargin = self.safe_number(position, 'maintainMargin')
          marginRatio = self.safe_number(position, 'marginRate')
          notional = self.safe_number(position, 'nominalValue')
          percentage = Precise.string_mul(self.safe_string(position, 'returnRate'), '100')
          timestamp = self.safe_number(position, 'createTime')
          return {
              'info': position,
              'symbol': symbol,
              'contracts': self.parse_number(contracts),
              'contractSize': None,
              'entryPrice': entryPrice,
              'collateral': None,
              'side': side,
              'unrealizedProfit': unrealizedProfit,
              'leverage': self.parse_number(leverage),
              'percentage': percentage,
              'marginMode': marginMode,
              'notional': notional,
              'markPrice': None,
              'liquidationPrice': liquidationPrice,
              'initialMargin': self.parse_number(initialMargin),
              'initialMarginPercentage': None,
              'maintenanceMargin': maintenanceMargin,
              'maintenanceMarginPercentage': None,
              'marginRatio': marginRatio,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
          }
  
      def parse_ledger_entry_type(self, type):
          types = {
              '1': 'realized pnl',
              '2': 'commission',
              '3': 'funding fee subtract',
              '4': 'funding fee addition',
              '5': 'insurance clear',
              '6': 'transfer in',
              '7': 'transfer out',
              '8': 'margin addition',
              '9': 'margin subtraction',
              '10': 'commission addition',
              '11': 'bill type freeze',
              '12': 'bill type unfreeze',
              '13': 'system take over margin',
              '14': 'transfer',
              '15': 'realized pnl collection',
              '16': 'funding fee collection',
              '17': 'recommender return commission',
              '18': 'by level subtract positions',
              '19': 'system add',
              '20': 'system subtract',
              '23': 'trading competition take over fund',
              '24': 'trading contest tickets',
              '25': 'return of trading contest tickets',
              '26': 'experience expired recall',
              '50': 'test register gift',
              '51': 'register gift',
              '52': 'deposit gift',
              '53': 'trading volume gift',
              '54': 'awards gift',
              '55': 'trading volume gift',
              '56': 'awards gift expire',
              '201': 'open positions',
              '202': 'close positions',
              '203': 'take over positions',
              '204': 'trading competition take over positions',
              '205': 'one way open long',
              '206': 'one way open short',
              '207': 'one way close long',
              '208': 'one way close short',
              '301': 'coupon deduction service charge',
              '302': 'experience deduction',
              '303': 'experience expired',
          }
          return self.safe_string(types, type, type)
  
      def parse_ledger_entry(self, item, currency=None):
          #
          #     [
          #         {
          #             "type": 3,
          #             "changeAmount": "0.00434664",
          #             "isIn": 0,
          #             "beforeAmount": "30.53353135",
          #             "beforeFreezeAmount": "21.547",
          #             "createTime": "1646121604997",
          #             "available": "30.52918471",
          #             "unit": "usdt",
          #             "symbol": "BTC_USDT"
          #         },
          #     ],
          #
          timestamp = self.safe_string(item, 'createTime')
          direction = None
          changeDirection = self.safe_number(item, 'isIn')
          if changeDirection == 1:
              direction = 'increase'
          else:
              direction = 'reduce'
          fee = None
          feeCost = self.safe_number(item, 'fee')
          if feeCost is not None:
              fee = {
                  'cost': feeCost,
                  'currency': self.safe_currency_code(self.safe_string(item, 'unit')),
              }
          return {
              'id': self.safe_string(item, 'id'),
              'info': item,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'direction': direction,
              'account': self.safe_string(item, 'userId'),
              'referenceId': None,
              'referenceAccount': None,
              'type': self.parse_ledger_entry_type(self.safe_integer(item, 'type')),
              'currency': self.safe_currency_code(self.safe_string(item, 'unit')),
              'amount': self.safe_number(item, 'changeAmount'),
              'before': self.safe_number(item, 'beforeAmount'),
              'after': self.safe_number(item, 'available'),
              'status': None,
              'fee': fee,
          }
  
      async def fetch_ledger(self, code=None, since=None, limit=None, params={}):
          if code is None:
              raise ArgumentsRequired(self.id + ' fetchLedger() requires a code argument')
          await self.load_markets()
          currency = self.currency(code)
          request = {
              'futuresAccountType': 1,
              # 'currencyId': '11',
              # 'type': 1,
              # 'endTime': self.milliseconds(),
              # 'pageNum': 1,
          }
          if code is not None:
              request['currencyName'] = currency['id']
          if since is not None:
              request['startTime'] = since
          if limit is not None:
              request['pageSize'] = limit
          response = await self.contractV2PrivateGetFundGetBill(self.extend(request, params))
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "list": [
          #                 {
          #                     "type": 3,
          #                     "changeAmount": "0.00434664",
          #                     "isIn": 0,
          #                     "beforeAmount": "30.53353135",
          #                     "beforeFreezeAmount": "21.547",
          #                     "createTime": "1646121604997",
          #                     "available": "30.52918471",
          #                     "unit": "usdt",
          #                     "symbol": "BTC_USDT"
          #                 },
          #             ],
          #             "pageNum": 1,
          #             "pageSize": 10
          #         },
          #         "desc": "操作成功"
          #     }
          #
          data = self.safe_value(response, 'data', {})
          list = self.safe_value(data, 'list', [])
          return self.parse_ledger(list, currency, since, limit)
  
      async def transfer(self, code, amount, fromAccount, toAccount, params={}):
          await self.load_markets()
          marketType, query = self.handle_market_type_and_params('transfer', None, params)
          currency = self.currency(code)
          margin = (marketType == 'margin')
          swap = (marketType == 'swap')
          side = None
          marginMethod = None
          amountToPrecision = self.currency_to_precision(code, amount)
          request = {
              'amount': amountToPrecision,  # Swap, Cross Margin, Isolated Margin
              # 'coin': currency['id'],  # Margin
              # 'currencyName': currency['id'],  # Swap
              # 'clientId': self.safe_string(params, 'clientId'),  # Swap "2sdfsdfsdf232342"
              # 'side': side,  # Swap, 1：Deposit(zb account -> futures account)，0：Withdrawal(futures account -> zb account)
              # 'marketName': self.safe_string(params, 'marketName'),  # Isolated Margin
          }
          if swap:
              if fromAccount == 'spot' or toAccount == 'future':
                  side = 1
              else:
                  side = 0
              request['currencyName'] = currency['id']
              request['clientId'] = self.safe_string(params, 'clientId')
              request['side'] = side
          else:
              defaultMargin = 'isolated' if margin else 'cross'
              marginMode = self.safe_string_2(self.options, 'defaultMarginMode', 'marginMode', defaultMargin)
              if marginMode == 'isolated':
                  if fromAccount == 'spot' or toAccount == 'isolated':
                      marginMethod = 'spotV1PrivateGetTransferInLever'
                  else:
                      marginMethod = 'spotV1PrivateGetTransferOutLever'
                  request['marketName'] = self.safe_string(params, 'marketName')
              elif marginMode == 'cross':
                  if fromAccount == 'spot' or toAccount == 'cross':
                      marginMethod = 'spotV1PrivateGetTransferInCross'
                  else:
                      marginMethod = 'spotV1PrivateGetTransferOutCross'
              request['coin'] = currency['id']
          method = self.get_supported_mapping(marketType, {
              'swap': 'contractV2PrivatePostFundTransferFund',
              'margin': marginMethod,
          })
          response = await getattr(self, method)(self.extend(request, query))
          #
          # Swap
          #
          #     {
          #         "code": 10000,
          #         "data": "2sdfsdfsdf232342",
          #         "desc": "Success"
          #     }
          #
          # Margin
          #
          #     {
          #         "code": 1000,
          #         "message": "Success"
          #     }
          #
          return self.extend(self.parse_transfer(response, currency), {
              'amount': self.parse_number(amountToPrecision),
              'fromAccount': fromAccount,
              'toAccount': toAccount,
          })
  
      def parse_transfer(self, transfer, currency=None):
          # response samples in 'transfer'
          timestamp = self.milliseconds()
          return {
              'id': self.safe_string(transfer, 'data'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'currency': self.safe_currency_code(None, 'currency'),
              'amount': None,
              'fromAccount': None,
              'toAccount': None,
              'status': None,
          }
  
      async def modify_margin_helper(self, symbol, amount, type, params={}):
          if params['positionsId'] is None:
              raise ArgumentsRequired(self.id + ' modifyMarginHelper() requires a positionsId argument in the params')
          await self.load_markets()
          market = self.market(symbol)
          amount = self.amount_to_precision(symbol, amount)
          position = self.safe_string(params, 'positionsId')
          request = {
              'positionsId': position,
              'amount': amount,
              'type': type,  # 1 increase, 0 reduce
              'futuresAccountType': 1,  # 1: USDT Perpetual Futures
          }
          response = await self.contractV2PrivatePostPositionsUpdateMargin(self.extend(request, params))
          #
          #     {
          #         "code": 10000,
          #         "data": {
          #             "amount": "0.002",
          #             "appendAmount": "0",
          #             "avgPrice": "43927.23",
          #             "bankruptcyPrice": "41730.86",
          #             "createTime": "1646208695609",
          #             "freezeAmount": "0",
          #             "id": "6900781818669377576",
          #             "keyMark": "6896693805014120448-100-1-",
          #             "lastAppendAmount": "0",
          #             "lastTime": "1646209235505",
          #             "leverage": 20,
          #             "liquidateLevel": 1,
          #             "liquidatePrice": "41898.46",
          #             "maintainMargin": "0",
          #             "margin": "4.392723",
          #             "marginAppendCount": 0,
          #             "marginBalance": "0",
          #             "marginMode": 1,
          #             "marginRate": "0",
          #             "marketId": "100",
          #             "marketName": "BTC_USDT",
          #             "modifyTime": "1646209235505",
          #             "nominalValue": "87.88828",
          #             "originAppendAmount": "0",
          #             "originId": "6904699716827818029",
          #             "positionsMode": 2,
          #             "sellerCurrencyId": "1",
          #             "side": 1,
          #             "status": 1,
          #             "unrealizedPnl": "0.03382",
          #             "usable": True,
          #             "userId": "6896693805014120448"
          #         },
          #         "desc":"操作成功"
          #     }
          #
          return self.extend(self.parse_margin_modification(response, market), {
              'amount': self.parse_number(amount),
          })
  
      def parse_margin_modification(self, data, market=None):
          innerData = self.safe_value(data, 'data', {})
          sideRaw = self.safe_integer(innerData, 'side')
          side = 'add' if (sideRaw == 1) else 'reduce'
          statusCode = self.safe_integer(innerData, 'status')
          status = 'ok' if (statusCode == 1) else 'failed'
          return {
              'info': data,
              'type': side,
              'amount': None,
              'code': market['quote'],
              'symbol': market['symbol'],
              'status': status,
          }
  
      async def add_margin(self, symbol, amount, params={}):
          if params['positionsId'] is None:
              raise ArgumentsRequired(self.id + ' addMargin() requires a positionsId argument in the params')
          return await self.modify_margin_helper(symbol, amount, 1, params)
  
      async def reduce_margin(self, symbol, amount, params={}):
          if params['positionsId'] is None:
              raise ArgumentsRequired(self.id + ' reduceMargin() requires a positionsId argument in the params')
          return await self.modify_margin_helper(symbol, amount, 0, params)
  
      async def fetch_borrow_rate(self, code, params={}):
          await self.load_markets()
          currency = self.currency(code)
          request = {
              'coin': currency['id'],
          }
          response = await self.spotV1PrivateGetGetLoans(self.extend(request, params))
          #
          #     {
          #         code: '1000',
          #         message: '操作成功',
          #         result: [
          #             {
          #                 interestRateOfDay: '0.0005',
          #                 repaymentDay: '30',
          #                 amount: '148804.4841',
          #                 balance: '148804.4841',
          #                 rateOfDayShow: '0.05 %',
          #                 coinName: 'USDT',
          #                 lowestAmount: '0.01'
          #             },
          #         ]
          #     }
          #
          timestamp = self.milliseconds()
          data = self.safe_value(response, 'result', [])
          rate = self.safe_value(data, 0, {})
          return {
              'currency': self.safe_currency_code(self.safe_string(rate, 'coinName')),
              'rate': self.safe_number(rate, 'interestRateOfDay'),
              'period': self.safe_number(rate, 'repaymentDay'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'info': rate,
          }
  
      async def fetch_borrow_rates(self, params={}):
          if params['coin'] is None:
              raise ArgumentsRequired(self.id + ' fetchBorrowRates() requires a coin argument in the params')
          await self.load_markets()
          currency = self.currency(self.safe_string(params, 'coin'))
          request = {
              'coin': currency['id'],
          }
          response = await self.spotV1PrivateGetGetLoans(self.extend(request, params))
          #
          #     {
          #         code: '1000',
          #         message: '操作成功',
          #         result: [
          #             {
          #                 interestRateOfDay: '0.0005',
          #                 repaymentDay: '30',
          #                 amount: '148804.4841',
          #                 balance: '148804.4841',
          #                 rateOfDayShow: '0.05 %',
          #                 coinName: 'USDT',
          #                 lowestAmount: '0.01'
          #             },
          #         ]
          #     }
          #
          timestamp = self.milliseconds()
          data = self.safe_value(response, 'result', [])
          rates = []
          for i in range(0, len(data)):
              entry = data[i]
              rates.append({
                  'currency': self.safe_currency_code(self.safe_string(entry, 'coinName')),
                  'rate': self.safe_number(entry, 'interestRateOfDay'),
                  'period': self.safe_number(entry, 'repaymentDay'),
                  'timestamp': timestamp,
                  'datetime': self.iso8601(timestamp),
                  'info': entry,
              })
          return rates
  
      def nonce(self):
          return self.milliseconds()
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          section, version, access = api
          url = self.implode_hostname(self.urls['api'][section][version][access])
          if access == 'public':
              if path == 'getFeeInfo':
                  url = self.implode_hostname(self.urls['api'][section][version]['private']) + '/' + path
              else:
                  url += '/' + version + '/' + path
              if params:
                  url += '?' + self.urlencode(params)
          elif section == 'contract':
              timestamp = self.milliseconds()
              iso8601 = self.iso8601(timestamp)
              signedString = iso8601 + method + '/Server/api/' + version + '/' + path
              params = self.keysort(params)
              headers = {
                  'ZB-APIKEY': self.apiKey,
                  'ZB-TIMESTAMP': iso8601,
                  # 'ZB-LAN': 'cn',  # cn, en, kr
              }
              url += '/' + version + '/' + path
              if method == 'POST':
                  headers['Content-Type'] = 'application/json'
                  body = self.json(params)
                  signedString += self.urlencode(params)
              else:
                  if params:
                      query = self.urlencode(params)
                      url += '?' + query
                      signedString += query
              secret = self.hash(self.encode(self.secret), 'sha1')
              signature = self.hmac(self.encode(signedString), self.encode(secret), hashlib.sha256, 'base64')
              headers['ZB-SIGN'] = signature
          else:
              query = self.keysort(self.extend({
                  'method': path,
                  'accesskey': self.apiKey,
              }, params))
              nonce = self.nonce()
              query = self.keysort(query)
              auth = self.rawencode(query)
              secret = self.hash(self.encode(self.secret), 'sha1')
              signature = self.hmac(self.encode(auth), self.encode(secret), hashlib.md5)
              suffix = 'sign=' + signature + '&reqTime=' + str(nonce)
              url += '/' + path + '?' + auth + '&' + suffix
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if response is None:
              return  # fallback to default error handler
          if body[0] == '{':
              feedback = self.id + ' ' + body
              self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
              if 'code' in response:
                  code = self.safe_string(response, 'code')
                  self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
                  if (code != '1000') and (code != '10000'):
                      raise ExchangeError(feedback)
              # special case for {"result":false,"message":"服务端忙碌"}(a "Busy Server" reply)
              result = self.safe_value(response, 'result')
              if result is not None:
                  if not result:
                      message = self.safe_string(response, 'message')
                      if message == u'服务端忙碌':
                          raise ExchangeNotAvailable(feedback)
                      else:
                          raise ExchangeError(feedback)
  