text: # -*- coding: utf-8 -*-
  
  # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
  
  from ccxt.base.exchange import Exchange
  import hashlib
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import PermissionDenied
  from ccxt.base.errors import AccountNotEnabled
  from ccxt.base.errors import AccountSuspended
  from ccxt.base.errors import ArgumentsRequired
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import BadSymbol
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import NotSupported
  from ccxt.base.errors import RateLimitExceeded
  from ccxt.base.errors import ExchangeNotAvailable
  from ccxt.base.decimal_to_precision import TICK_SIZE
  from ccxt.base.precise import Precise
  
  
  class gateio(Exchange):
  
      def describe(self):
          return self.deep_extend(super(gateio, self).describe(), {
              'id': 'gateio',
              'name': 'Gate.io',
              'countries': ['KR'],
              'rateLimit': 10 / 3,  # 300 requests per second or 3.33ms
              'version': 'v4',
              'certified': True,
              'pro': True,
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/31784029-0313c702-b509-11e7-9ccc-bc0da6a0e435.jpg',
                  'doc': 'https://www.gate.io/docs/apiv4/en/index.html',
                  'www': 'https://gate.io/',
                  'api': {
                      'public': {
                          'wallet': 'https://api.gateio.ws/api/v4',
                          'futures': 'https://api.gateio.ws/api/v4',
                          'margin': 'https://api.gateio.ws/api/v4',
                          'delivery': 'https://api.gateio.ws/api/v4',
                          'spot': 'https://api.gateio.ws/api/v4',
                          'options': 'https://api.gateio.ws/api/v4',
                      },
                      'private': {
                          'withdrawals': 'https://api.gateio.ws/api/v4',
                          'wallet': 'https://api.gateio.ws/api/v4',
                          'futures': 'https://api.gateio.ws/api/v4',
                          'margin': 'https://api.gateio.ws/api/v4',
                          'delivery': 'https://api.gateio.ws/api/v4',
                          'spot': 'https://api.gateio.ws/api/v4',
                          'options': 'https://api.gateio.ws/api/v4',
                      },
                  },
                  'test': {
                      'public': {
                          'futures': 'https://fx-api-testnet.gateio.ws/api/v4',
                          'delivery': 'https://fx-api-testnet.gateio.ws/api/v4',
                      },
                      'private': {
                          'futures': 'https://fx-api-testnet.gateio.ws/api/v4',
                          'delivery': 'https://fx-api-testnet.gateio.ws/api/v4',
                      },
                  },
                  'referral': {
                      'url': 'https://www.gate.io/ref/2436035',
                      'discount': 0.2,
                  },
              },
              'has': {
                  'CORS': None,
                  'spot': True,
                  'margin': True,
                  'swap': True,
                  'future': True,
                  'option': None,
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'createMarketOrder': False,
                  'createOrder': True,
                  'createPostOnlyOrder': True,
                  'createStopLimitOrder': True,
                  'createStopMarketOrder': False,
                  'createStopOrder': True,
                  'fetchBalance': True,
                  'fetchBorrowRate': False,
                  'fetchBorrowRateHistories': False,
                  'fetchBorrowRateHistory': False,
                  'fetchBorrowRates': False,
                  'fetchClosedOrders': True,
                  'fetchCurrencies': True,
                  'fetchDepositAddress': True,
                  'fetchDeposits': True,
                  'fetchFundingHistory': True,
                  'fetchFundingRate': True,
                  'fetchFundingRateHistory': True,
                  'fetchFundingRates': True,
                  'fetchIndexOHLCV': True,
                  'fetchLeverage': False,
                  'fetchLeverageTiers': True,
                  'fetchMarketLeverageTiers': 'emulated',
                  'fetchMarkets': True,
                  'fetchMarkOHLCV': True,
                  'fetchMyTrades': True,
                  'fetchNetworkDepositAddress': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchPositions': True,
                  'fetchPremiumIndexOHLCV': False,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTime': False,
                  'fetchTrades': True,
                  'fetchTradingFee': True,
                  'fetchTradingFees': True,
                  'fetchTransactionFees': True,
                  'fetchWithdrawals': True,
                  'setLeverage': True,
                  'setMarginMode': False,
                  'transfer': True,
                  'withdraw': True,
              },
              'api': {
                  'public': {
                      'wallet': {
                          'get': {
                              'wallet/currency_chains': 1.5,
                          },
                      },
                      'spot': {
                          'get': {
                              'currencies': 1,
                              'currencies/{currency}': 1,
                              'currency_pairs': 1,
                              'currency_pairs/{currency_pair}': 1,
                              'tickers': 1,
                              'order_book': 1,
                              'trades': 1,
                              'candlesticks': 1,
                          },
                      },
                      'margin': {
                          'get': {
                              'currency_pairs': 1,
                              'currency_pairs/{currency_pair}': 1,
                              'cross/currencies': 1,
                              'cross/currencies/{currency}': 1,
                              'funding_book': 1,
                          },
                      },
                      'futures': {
                          'get': {
                              '{settle}/contracts': 1.5,
                              '{settle}/contracts/{contract}': 1.5,
                              '{settle}/order_book': 1.5,
                              '{settle}/trades': 1.5,
                              '{settle}/candlesticks': 1.5,
                              '{settle}/tickers': 1.5,
                              '{settle}/funding_rate': 1.5,
                              '{settle}/insurance': 1.5,
                              '{settle}/contract_stats': 1.5,
                              '{settle}/liq_orders': 1.5,
                          },
                      },
                      'delivery': {
                          'get': {
                              '{settle}/contracts': 1.5,
                              '{settle}/contracts/{contract}': 1.5,
                              '{settle}/order_book': 1.5,
                              '{settle}/trades': 1.5,
                              '{settle}/candlesticks': 1.5,
                              '{settle}/tickers': 1.5,
                              '{settle}/insurance': 1.5,
                          },
                      },
                      'options': {
                          'get': {
                              'underlyings': 1.5,
                              'expirations': 1.5,
                              'contracts': 1.5,
                              'contracts/{contract}': 1.5,
                              'settlements': 1.5,
                              'settlements/{contract}': 1.5,
                              'order_book': 1.5,
                              'tickers': 1.5,
                              'underlying/tickers/{underlying}': 1.5,
                              'candlesticks': 1.5,
                              'underlying/candlesticks': 1.5,
                              'trades': 1.5,
                          },
                      },
                  },
                  'private': {
                      'withdrawals': {
                          'post': {
                              '': 3000,  # 3000 = 10 seconds
                          },
                          'delete': {
                              '{withdrawal_id}': 300,
                          },
                      },
                      'wallet': {
                          'get': {
                              'deposit_address': 300,
                              'withdrawals': 300,
                              'deposits': 300,
                              'sub_account_transfers': 300,
                              'withdraw_status': 300,
                              'sub_account_balances': 300,
                              'fee': 300,
                              'total_balance': 300,
                          },
                          'post': {
                              'transfers': 300,
                              'sub_account_transfers': 300,
                          },
                      },
                      'spot': {
                          'get': {
                              'accounts': 1,
                              'open_orders': 1,
                              'orders': 1,
                              'orders/{order_id}': 1,
                              'my_trades': 1,
                              'price_orders': 1,
                              'price_orders/{order_id}': 1,
                          },
                          'post': {
                              'batch_orders': 1,
                              'orders': 1,
                              'cancel_batch_orders': 1,
                              'price_orders': 1,
                          },
                          'delete': {
                              'orders': 1,
                              'orders/{order_id}': 1,
                              'price_orders': 1,
                              'price_orders/{order_id}': 1,
                          },
                      },
                      'margin': {
                          'get': {
                              'accounts': 1.5,
                              'account_book': 1.5,
                              'funding_accounts': 1.5,
                              'loans': 1.5,
                              'loans/{loan_id}': 1.5,
                              'loans/{loan_id}/repayment': 1.5,
                              'loan_records': 1.5,
                              'loan_records/{load_record_id}': 1.5,
                              'auto_repay': 1.5,
                              'transferable': 1.5,
                              'cross/accounts': 1.5,
                              'cross/account_book': 1.5,
                              'cross/loans': 1.5,
                              'cross/loans/{loan_id}': 1.5,
                              'cross/loans/repayments': 1.5,
                              'cross/transferable': 1.5,
                              'loan_records/{loan_record_id}': 1.5,
                              'borrowable': 1.5,
                              'cross/repayments': 1.5,
                              'cross/borrowable': 1.5,
                          },
                          'post': {
                              'loans': 1.5,
                              'merged_loans': 1.5,
                              'loans/{loan_id}/repayment': 1.5,
                              'auto_repay': 1.5,
                              'cross/loans': 1.5,
                              'cross/loans/repayments': 1.5,
                              'cross/repayments': 1.5,
                          },
                          'patch': {
                              'loans/{loan_id}': 1.5,
                              'loan_records/{loan_record_id}': 1.5,
                          },
                          'delete': {
                              'loans/{loan_id}': 1.5,
                          },
                      },
                      'futures': {
                          'get': {
                              '{settle}/accounts': 1.5,
                              '{settle}/account_book': 1.5,
                              '{settle}/positions': 1.5,
                              '{settle}/positions/{contract}': 1.5,
                              '{settle}/orders': 1.5,
                              '{settle}/orders/{order_id}': 1.5,
                              '{settle}/my_trades': 1.5,
                              '{settle}/position_close': 1.5,
                              '{settle}/liquidates': 1.5,
                              '{settle}/price_orders': 1.5,
                              '{settle}/price_orders/{order_id}': 1.5,
                              '{settle}/dual_comp/positions/{contract}': 1.5,
                          },
                          'post': {
                              '{settle}/positions/{contract}/margin': 1.5,
                              '{settle}/positions/{contract}/leverage': 1.5,
                              '{settle}/positions/{contract}/risk_limit': 1.5,
                              '{settle}/dual_mode': 1.5,
                              '{settle}/dual_comp/positions/{contract}': 1.5,
                              '{settle}/dual_comp/positions/{contract}/margin': 1.5,
                              '{settle}/dual_comp/positions/{contract}/leverage': 1.5,
                              '{settle}/dual_comp/positions/{contract}/risk_limit': 1.5,
                              '{settle}/orders': 1.5,
                              '{settle}/price_orders': 1.5,
                          },
                          'delete': {
                              '{settle}/orders': 1.5,
                              '{settle}/orders/{order_id}': 1.5,
                              '{settle}/price_orders': 1.5,
                              '{settle}/price_orders/{order_id}': 1.5,
                          },
                      },
                      'delivery': {
                          'get': {
                              '{settle}/accounts': 1.5,
                              '{settle}/account_book': 1.5,
                              '{settle}/positions': 1.5,
                              '{settle}/positions/{contract}': 1.5,
                              '{settle}/orders': 1.5,
                              '{settle}/orders/{order_id}': 1.5,
                              '{settle}/my_trades': 1.5,
                              '{settle}/position_close': 1.5,
                              '{settle}/liquidates': 1.5,
                              '{settle}/price_orders': 1.5,
                              '{settle}/price_orders/{order_id}': 1.5,
                              '{settle}/settlements': 1.5,
                          },
                          'post': {
                              '{settle}/positions/{contract}/margin': 1.5,
                              '{settle}/positions/{contract}/leverage': 1.5,
                              '{settle}/positions/{contract}/risk_limit': 1.5,
                              '{settle}/orders': 1.5,
                              '{settle}/price_orders': 1.5,
                          },
                          'delete': {
                              '{settle}/orders': 1.5,
                              '{settle}/orders/{order_id}': 1.5,
                              '{settle}/price_orders': 1.5,
                              '{settle}/price_orders/{order_id}': 1.5,
                          },
                      },
                      'options': {
                          'get': {
                              'accounts': 1.5,
                              'account_book': 1.5,
                              'positions': 1.5,
                              'positions/{contract}': 1.5,
                              'position_close': 1.5,
                              'orders': 1.5,
                              'orders/{order_id}': 1.5,
                              'my_trades': 1.5,
                          },
                          'post': {
                              'orders': 1.5,
                          },
                          'delete': {
                              'orders': 1.5,
                              'orders/{order_id}': 1.5,
                          },
                      },
                  },
              },
              'timeframes': {
                  '10s': '10s',
                  '1m': '1m',
                  '5m': '5m',
                  '15m': '15m',
                  '30m': '30m',
                  '1h': '1h',
                  '4h': '4h',
                  '8h': '8h',
                  '1d': '1d',
                  '7d': '7d',
                  '1w': '7d',
              },
              # copied from gateiov2
              'commonCurrencies': {
                  '88MPH': 'MPH',
                  'AXIS': 'Axis DeFi',
                  'BIFI': 'Bitcoin File',
                  'BOX': 'DefiBox',
                  'BTCBEAR': 'BEAR',
                  'BTCBULL': 'BULL',
                  'BYN': 'BeyondFi',
                  'EGG': 'Goose Finance',
                  'GTC': 'Game.com',  # conflict with Gitcoin and Gastrocoin
                  'GTC_HT': 'Game.com HT',
                  'GTC_BSC': 'Game.com BSC',
                  'HIT': 'HitChain',
                  'MM': 'Million',  # conflict with MilliMeter
                  'MPH': 'Morpher',  # conflict with 88MPH
                  'RAI': 'Rai Reflex Index',  # conflict with RAI Finance
                  'SBTC': 'Super Bitcoin',
                  'TNC': 'Trinity Network Credit',
                  'TON': 'TONToken',
                  'VAI': 'VAIOT',
              },
              'requiredCredentials': {
                  'apiKey': True,
                  'secret': True,
              },
              'headers': {
                  'X-Gate-Channel-Id': 'ccxt',
              },
              'options': {
                  'createOrder': {
                      'expiration': 86400,  # for conditional orders
                  },
                  'networks': {
                      'TRC20': 'TRX',
                      'ERC20': 'ETH',
                      'BEP20': 'BSC',
                  },
                  'accountsByType': {
                      'funding': 'spot',
                      'spot': 'spot',
                      'margin': 'margin',
                      'cross_margin': 'cross_margin',
                      'cross': 'cross_margin',
                      'isolated': 'margin',
                      'swap': 'futures',
                      'future': 'delivery',
                      'futures': 'futures',
                      'delivery': 'delivery',
                  },
                  'defaultType': 'spot',
                  'swap': {
                      'fetchMarkets': {
                          'settlementCurrencies': ['usdt', 'btc'],
                      },
                  },
                  'future': {
                      'fetchMarkets': {
                          'settlementCurrencies': ['usdt', 'btc'],
                      },
                  },
              },
              'precisionMode': TICK_SIZE,
              'fees': {
                  'trading': {
                      'tierBased': True,
                      'feeSide': 'get',
                      'percentage': True,
                      'maker': self.parse_number('0.002'),
                      'taker': self.parse_number('0.002'),
                      'tiers': {
                          # volume is in BTC
                          'maker': [
                              [self.parse_number('0'), self.parse_number('0.002')],
                              [self.parse_number('1.5'), self.parse_number('0.00185')],
                              [self.parse_number('3'), self.parse_number('0.00175')],
                              [self.parse_number('6'), self.parse_number('0.00165')],
                              [self.parse_number('12.5'), self.parse_number('0.00155')],
                              [self.parse_number('25'), self.parse_number('0.00145')],
                              [self.parse_number('75'), self.parse_number('0.00135')],
                              [self.parse_number('200'), self.parse_number('0.00125')],
                              [self.parse_number('500'), self.parse_number('0.00115')],
                              [self.parse_number('1250'), self.parse_number('0.00105')],
                              [self.parse_number('2500'), self.parse_number('0.00095')],
                              [self.parse_number('3000'), self.parse_number('0.00085')],
                              [self.parse_number('6000'), self.parse_number('0.00075')],
                              [self.parse_number('11000'), self.parse_number('0.00065')],
                              [self.parse_number('20000'), self.parse_number('0.00055')],
                              [self.parse_number('40000'), self.parse_number('0.00055')],
                              [self.parse_number('75000'), self.parse_number('0.00055')],
                          ],
                          'taker': [
                              [self.parse_number('0'), self.parse_number('0.002')],
                              [self.parse_number('1.5'), self.parse_number('0.00195')],
                              [self.parse_number('3'), self.parse_number('0.00185')],
                              [self.parse_number('6'), self.parse_number('0.00175')],
                              [self.parse_number('12.5'), self.parse_number('0.00165')],
                              [self.parse_number('25'), self.parse_number('0.00155')],
                              [self.parse_number('75'), self.parse_number('0.00145')],
                              [self.parse_number('200'), self.parse_number('0.00135')],
                              [self.parse_number('500'), self.parse_number('0.00125')],
                              [self.parse_number('1250'), self.parse_number('0.00115')],
                              [self.parse_number('2500'), self.parse_number('0.00105')],
                              [self.parse_number('3000'), self.parse_number('0.00095')],
                              [self.parse_number('6000'), self.parse_number('0.00085')],
                              [self.parse_number('11000'), self.parse_number('0.00075')],
                              [self.parse_number('20000'), self.parse_number('0.00065')],
                              [self.parse_number('40000'), self.parse_number('0.00065')],
                              [self.parse_number('75000'), self.parse_number('0.00065')],
                          ],
                      },
                  },
                  'swap': {
                      'tierBased': True,
                      'feeSide': 'base',
                      'percentage': True,
                      'maker': self.parse_number('0.0'),
                      'taker': self.parse_number('0.0005'),
                      'tiers': {
                          'maker': [
                              [self.parse_number('0'), self.parse_number('0.0000')],
                              [self.parse_number('1.5'), self.parse_number('-0.00005')],
                              [self.parse_number('3'), self.parse_number('-0.00005')],
                              [self.parse_number('6'), self.parse_number('-0.00005')],
                              [self.parse_number('12.5'), self.parse_number('-0.00005')],
                              [self.parse_number('25'), self.parse_number('-0.00005')],
                              [self.parse_number('75'), self.parse_number('-0.00005')],
                              [self.parse_number('200'), self.parse_number('-0.00005')],
                              [self.parse_number('500'), self.parse_number('-0.00005')],
                              [self.parse_number('1250'), self.parse_number('-0.00005')],
                              [self.parse_number('2500'), self.parse_number('-0.00005')],
                              [self.parse_number('3000'), self.parse_number('-0.00008')],
                              [self.parse_number('6000'), self.parse_number('-0.01000')],
                              [self.parse_number('11000'), self.parse_number('-0.01002')],
                              [self.parse_number('20000'), self.parse_number('-0.01005')],
                              [self.parse_number('40000'), self.parse_number('-0.02000')],
                              [self.parse_number('75000'), self.parse_number('-0.02005')],
                          ],
                          'taker': [
                              [self.parse_number('0'), self.parse_number('0.00050')],
                              [self.parse_number('1.5'), self.parse_number('0.00048')],
                              [self.parse_number('3'), self.parse_number('0.00046')],
                              [self.parse_number('6'), self.parse_number('0.00044')],
                              [self.parse_number('12.5'), self.parse_number('0.00042')],
                              [self.parse_number('25'), self.parse_number('0.00040')],
                              [self.parse_number('75'), self.parse_number('0.00038')],
                              [self.parse_number('200'), self.parse_number('0.00036')],
                              [self.parse_number('500'), self.parse_number('0.00034')],
                              [self.parse_number('1250'), self.parse_number('0.00032')],
                              [self.parse_number('2500'), self.parse_number('0.00030')],
                              [self.parse_number('3000'), self.parse_number('0.00030')],
                              [self.parse_number('6000'), self.parse_number('0.00030')],
                              [self.parse_number('11000'), self.parse_number('0.00030')],
                              [self.parse_number('20000'), self.parse_number('0.00030')],
                              [self.parse_number('40000'), self.parse_number('0.00030')],
                              [self.parse_number('75000'), self.parse_number('0.00030')],
                          ],
                      },
                  },
              },
              # https://www.gate.io/docs/apiv4/en/index.html#label-list
              'exceptions': {
                  'exact': {
                      'INVALID_PARAM_VALUE': BadRequest,
                      'INVALID_PROTOCOL': BadRequest,
                      'INVALID_ARGUMENT': BadRequest,
                      'INVALID_REQUEST_BODY': BadRequest,
                      'MISSING_REQUIRED_PARAM': ArgumentsRequired,
                      'BAD_REQUEST': BadRequest,
                      'INVALID_CONTENT_TYPE': BadRequest,
                      'NOT_ACCEPTABLE': BadRequest,
                      'METHOD_NOT_ALLOWED': BadRequest,
                      'NOT_FOUND': ExchangeError,
                      'INVALID_CREDENTIALS': AuthenticationError,
                      'INVALID_KEY': AuthenticationError,
                      'IP_FORBIDDEN': AuthenticationError,
                      'READ_ONLY': PermissionDenied,
                      'INVALID_SIGNATURE': AuthenticationError,
                      'MISSING_REQUIRED_HEADER': AuthenticationError,
                      'REQUEST_EXPIRED': AuthenticationError,
                      'ACCOUNT_LOCKED': AccountSuspended,
                      'FORBIDDEN': PermissionDenied,
                      'SUB_ACCOUNT_NOT_FOUND': ExchangeError,
                      'SUB_ACCOUNT_LOCKED': AccountSuspended,
                      'MARGIN_BALANCE_EXCEPTION': ExchangeError,
                      'MARGIN_TRANSFER_FAILED': ExchangeError,
                      'TOO_MUCH_FUTURES_AVAILABLE': ExchangeError,
                      'FUTURES_BALANCE_NOT_ENOUGH': InsufficientFunds,
                      'ACCOUNT_EXCEPTION': ExchangeError,
                      'SUB_ACCOUNT_TRANSFER_FAILED': ExchangeError,
                      'ADDRESS_NOT_USED': ExchangeError,
                      'TOO_FAST': RateLimitExceeded,
                      'WITHDRAWAL_OVER_LIMIT': ExchangeError,
                      'API_WITHDRAW_DISABLED': ExchangeNotAvailable,
                      'INVALID_WITHDRAW_ID': ExchangeError,
                      'INVALID_WITHDRAW_CANCEL_STATUS': ExchangeError,
                      'INVALID_PRECISION': InvalidOrder,
                      'INVALID_CURRENCY': BadSymbol,
                      'INVALID_CURRENCY_PAIR': BadSymbol,
                      'POC_FILL_IMMEDIATELY': ExchangeError,
                      'ORDER_NOT_FOUND': OrderNotFound,
                      'CLIENT_ID_NOT_FOUND': OrderNotFound,
                      'ORDER_CLOSED': InvalidOrder,
                      'ORDER_CANCELLED': InvalidOrder,
                      'QUANTITY_NOT_ENOUGH': InvalidOrder,
                      'BALANCE_NOT_ENOUGH': InsufficientFunds,
                      'MARGIN_NOT_SUPPORTED': InvalidOrder,
                      'MARGIN_BALANCE_NOT_ENOUGH': InsufficientFunds,
                      'AMOUNT_TOO_LITTLE': InvalidOrder,
                      'AMOUNT_TOO_MUCH': InvalidOrder,
                      'REPEATED_CREATION': InvalidOrder,
                      'LOAN_NOT_FOUND': OrderNotFound,
                      'LOAN_RECORD_NOT_FOUND': OrderNotFound,
                      'NO_MATCHED_LOAN': ExchangeError,
                      'NOT_MERGEABLE': ExchangeError,
                      'NO_CHANGE': ExchangeError,
                      'REPAY_TOO_MUCH': ExchangeError,
                      'TOO_MANY_CURRENCY_PAIRS': InvalidOrder,
                      'TOO_MANY_ORDERS': InvalidOrder,
                      'MIXED_ACCOUNT_TYPE': InvalidOrder,
                      'AUTO_BORROW_TOO_MUCH': ExchangeError,
                      'TRADE_RESTRICTED': InsufficientFunds,
                      'USER_NOT_FOUND': AccountNotEnabled,
                      'CONTRACT_NO_COUNTER': ExchangeError,
                      'CONTRACT_NOT_FOUND': BadSymbol,
                      'RISK_LIMIT_EXCEEDED': ExchangeError,
                      'INSUFFICIENT_AVAILABLE': InsufficientFunds,
                      'LIQUIDATE_IMMEDIATELY': InvalidOrder,
                      'LEVERAGE_TOO_HIGH': InvalidOrder,
                      'LEVERAGE_TOO_LOW': InvalidOrder,
                      'ORDER_NOT_OWNED': ExchangeError,
                      'ORDER_FINISHED': ExchangeError,
                      'POSITION_CROSS_MARGIN': ExchangeError,
                      'POSITION_IN_LIQUIDATION': ExchangeError,
                      'POSITION_IN_CLOSE': ExchangeError,
                      'POSITION_EMPTY': InvalidOrder,
                      'REMOVE_TOO_MUCH': ExchangeError,
                      'RISK_LIMIT_NOT_MULTIPLE': ExchangeError,
                      'RISK_LIMIT_TOO_HIGH': ExchangeError,
                      'RISK_LIMIT_TOO_lOW': ExchangeError,
                      'PRICE_TOO_DEVIATED': InvalidOrder,
                      'SIZE_TOO_LARGE': InvalidOrder,
                      'SIZE_TOO_SMALL': InvalidOrder,
                      'PRICE_OVER_LIQUIDATION': InvalidOrder,
                      'PRICE_OVER_BANKRUPT': InvalidOrder,
                      'ORDER_POC_IMMEDIATE': InvalidOrder,
                      'INCREASE_POSITION': InvalidOrder,
                      'CONTRACT_IN_DELISTING': ExchangeError,
                      'INTERNAL': ExchangeNotAvailable,
                      'SERVER_ERROR': ExchangeNotAvailable,
                      'TOO_BUSY': ExchangeNotAvailable,
                      'CROSS_ACCOUNT_NOT_FOUND': ExchangeError,
                  },
              },
              'broad': {},
          })
  
      def fetch_markets(self, params={}):
          result = []
          type, query = self.handle_market_type_and_params('fetchMarkets', None, params)
          if type == 'spot' or type == 'margin':
              result = self.fetch_spot_markets(query)
          if type == 'swap' or type == 'future':
              result = self.fetch_contract_markets(query)  # futures and swaps
          if type == 'option':
              result = self.fetch_option_markets(query)
          resultLength = len(result)
          if resultLength == 0:
              raise ExchangeError(self.id + " does not support '" + type + "' type, set exchange.options['defaultType'] to " + "'spot', 'margin', 'swap', 'future' or 'option'")  # eslint-disable-line quotes
          return result
  
      def fetch_spot_markets(self, params):
          marginResponse = self.publicMarginGetCurrencyPairs(params)
          spotMarketsResponse = self.publicSpotGetCurrencyPairs(params)
          marginMarkets = self.index_by(marginResponse, 'id')
          #
          #  Spot
          #
          #     [
          #         {
          #             "id": "QTUM_ETH",
          #             "base": "QTUM",
          #             "quote": "ETH",
          #             "fee": "0.2",
          #             "min_base_amount": "0.01",
          #             "min_quote_amount": "0.001",
          #             "amount_precision": 3,
          #             "precision": 6,
          #             "trade_status": "tradable",
          #             "sell_start": 0,
          #             "buy_start": 0
          #         }
          #     ]
          #
          #  Margin
          #
          #     [
          #         {
          #             "id": "ETH_USDT",
          #             "base": "ETH",
          #             "quote": "USDT",
          #             "leverage": 3,
          #             "min_base_amount": "0.01",
          #             "min_quote_amount": "100",
          #             "max_quote_amount": "1000000"
          #         }
          #     ]
          #
          result = []
          for i in range(0, len(spotMarketsResponse)):
              spotMarket = spotMarketsResponse[i]
              id = self.safe_string(spotMarket, 'id')
              marginMarket = self.safe_value(marginMarkets, id)
              market = self.deep_extend(marginMarket, spotMarket)
              baseId, quoteId = id.split('_')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              takerPercent = self.safe_string(market, 'fee')
              makerPercent = self.safe_string(market, 'maker_fee_rate', takerPercent)
              amountPrecisionString = self.safe_string(market, 'amount_precision')
              pricePrecisionString = self.safe_string(market, 'precision')
              tradeStatus = self.safe_string(market, 'trade_status')
              leverage = self.safe_number(market, 'leverage')
              defaultMinAmountLimit = self.parse_number(self.parse_precision(amountPrecisionString))
              margin = leverage is not None
              result.append({
                  'id': id,
                  'symbol': base + '/' + quote,
                  'base': base,
                  'quote': quote,
                  'settle': None,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'settleId': None,
                  'type': 'spot',
                  'spot': True,
                  'margin': margin,
                  'swap': False,
                  'future': False,
                  'option': False,
                  'active': (tradeStatus == 'tradable'),
                  'contract': False,
                  'linear': None,
                  'inverse': None,
                  # Fee is in %, so divide by 100
                  'taker': self.parse_number(Precise.string_div(takerPercent, '100')),
                  'maker': self.parse_number(Precise.string_div(makerPercent, '100')),
                  'contractSize': None,
                  'expiry': None,
                  'expiryDatetime': None,
                  'strike': None,
                  'optionType': None,
                  'precision': {
                      'amount': self.parse_number(self.parse_precision(amountPrecisionString)),
                      'price': self.parse_number(self.parse_precision(pricePrecisionString)),
                  },
                  'limits': {
                      'leverage': {
                          'min': self.parse_number('1'),
                          'max': self.safe_number(market, 'leverage', 1),
                      },
                      'amount': {
                          'min': self.safe_number(spotMarket, 'min_base_amount', defaultMinAmountLimit),
                          'max': None,
                      },
                      'price': {
                          'min': None,
                          'max': None,
                      },
                      'cost': {
                          'min': self.safe_number(market, 'min_quote_amount'),
                          'max': self.safe_number(market, 'max_quote_amount'),
                      },
                  },
                  'info': market,
              })
          return result
  
      def fetch_contract_markets(self, params):
          result = []
          swapSettlementCurrencies = self.get_settlement_currencies('swap', 'fetchMarkets')
          futureSettlementCurrencies = self.get_settlement_currencies('future', 'fetchMarkets')
          for c in range(0, len(swapSettlementCurrencies)):
              settleId = swapSettlementCurrencies[c]
              query = params
              query['settle'] = settleId
              response = self.publicFuturesGetSettleContracts(query)
              for i in range(0, len(response)):
                  parsedMarket = self.parse_contract_market(response[i], settleId)
                  result.append(parsedMarket)
          for c in range(0, len(futureSettlementCurrencies)):
              settleId = futureSettlementCurrencies[c]
              query = params
              query['settle'] = settleId
              response = self.publicDeliveryGetSettleContracts(query)
              for i in range(0, len(response)):
                  parsedMarket = self.parse_contract_market(response[i], settleId)
                  result.append(parsedMarket)
          return result
  
      def parse_contract_market(self, market, settleId):
          #
          #  Perpetual swap
          #
          #    {
          #        "name": "BTC_USDT",
          #        "type": "direct",
          #        "quanto_multiplier": "0.0001",
          #        "ref_discount_rate": "0",
          #        "order_price_deviate": "0.5",
          #        "maintenance_rate": "0.005",
          #        "mark_type": "index",
          #        "last_price": "38026",
          #        "mark_price": "37985.6",
          #        "index_price": "37954.92",
          #        "funding_rate_indicative": "0.000219",
          #        "mark_price_round": "0.01",
          #        "funding_offset": 0,
          #        "in_delisting": False,
          #        "risk_limit_base": "1000000",
          #        "interest_rate": "0.0003",
          #        "order_price_round": "0.1",
          #        "order_size_min": 1,
          #        "ref_rebate_rate": "0.2",
          #        "funding_interval": 28800,
          #        "risk_limit_step": "1000000",
          #        "leverage_min": "1",
          #        "leverage_max": "100",
          #        "risk_limit_max": "8000000",
          #        "maker_fee_rate": "-0.00025",
          #        "taker_fee_rate": "0.00075",
          #        "funding_rate": "0.002053",
          #        "order_size_max": 1000000,
          #        "funding_next_apply": 1610035200,
          #        "short_users": 977,
          #        "config_change_time": 1609899548,
          #        "trade_size": 28530850594,
          #        "position_size": 5223816,
          #        "long_users": 455,
          #        "funding_impact_value": "60000",
          #        "orders_limit": 50,
          #        "trade_id": 10851092,
          #        "orderbook_id": 2129638396
          #    }
          #
          #  Delivery Futures
          #
          #    {
          #        "name": "BTC_USDT_20200814",
          #        "underlying": "BTC_USDT",
          #        "cycle": "WEEKLY",
          #        "type": "direct",
          #        "quanto_multiplier": "0.0001",
          #        "mark_type": "index",
          #        "last_price": "9017",
          #        "mark_price": "9019",
          #        "index_price": "9005.3",
          #        "basis_rate": "0.185095",
          #        "basis_value": "13.7",
          #        "basis_impact_value": "100000",
          #        "settle_price": "0",
          #        "settle_price_interval": 60,
          #        "settle_price_duration": 1800,
          #        "settle_fee_rate": "0.0015",
          #        "expire_time": 1593763200,
          #        "order_price_round": "0.1",
          #        "mark_price_round": "0.1",
          #        "leverage_min": "1",
          #        "leverage_max": "100",
          #        "maintenance_rate": "1000000",
          #        "risk_limit_base": "140.726652109199",
          #        "risk_limit_step": "1000000",
          #        "risk_limit_max": "8000000",
          #        "maker_fee_rate": "-0.00025",
          #        "taker_fee_rate": "0.00075",
          #        "ref_discount_rate": "0",
          #        "ref_rebate_rate": "0.2",
          #        "order_price_deviate": "0.5",
          #        "order_size_min": 1,
          #        "order_size_max": 1000000,
          #        "orders_limit": 50,
          #        "orderbook_id": 63,
          #        "trade_id": 26,
          #        "trade_size": 435,
          #        "position_size": 130,
          #        "config_change_time": 1593158867,
          #        "in_delisting": False
          #    }
          #
          id = self.safe_string(market, 'name')
          parts = id.split('_')
          baseId = self.safe_string(parts, 0)
          quoteId = self.safe_string(parts, 1)
          date = self.safe_string(parts, 2)
          base = self.safe_currency_code(baseId)
          quote = self.safe_currency_code(quoteId)
          settle = self.safe_currency_code(settleId)
          expiry = self.safe_timestamp(market, 'expire_time')
          symbol = ''
          marketType = 'swap'
          if date is not None:
              symbol = base + '/' + quote + ':' + settle + '-' + self.yymmdd(expiry, '')
              marketType = 'future'
          else:
              symbol = base + '/' + quote + ':' + settle
          priceDeviate = self.safe_string(market, 'order_price_deviate')
          markPrice = self.safe_string(market, 'mark_price')
          minMultiplier = Precise.string_sub('1', priceDeviate)
          maxMultiplier = Precise.string_add('1', priceDeviate)
          minPrice = Precise.string_mul(minMultiplier, markPrice)
          maxPrice = Precise.string_mul(maxMultiplier, markPrice)
          takerPercent = self.safe_string(market, 'taker_fee_rate')
          makerPercent = self.safe_string(market, 'maker_fee_rate', takerPercent)
          isLinear = quote == settle
          return {
              'id': id,
              'symbol': symbol,
              'base': base,
              'quote': quote,
              'settle': settle,
              'baseId': baseId,
              'quoteId': quoteId,
              'settleId': settleId,
              'type': marketType,
              'spot': False,
              'margin': False,
              'swap': marketType == 'swap',
              'future': marketType == 'future',
              'option': marketType == 'option',
              'active': True,
              'contract': True,
              'linear': isLinear,
              'inverse': not isLinear,
              'taker': self.parse_number(Precise.string_div(takerPercent, '100')),  # Fee is in %, so divide by 100
              'maker': self.parse_number(Precise.string_div(makerPercent, '100')),
              'contractSize': self.safe_number(market, 'quanto_multiplier'),
              'expiry': expiry,
              'expiryDatetime': self.iso8601(expiry),
              'strike': None,
              'optionType': None,
              'precision': {
                  'amount': self.parse_number('1'),
                  'price': self.safe_number(market, 'order_price_round'),
              },
              'limits': {
                  'leverage': {
                      'min': self.safe_number(market, 'leverage_min'),
                      'max': self.safe_number(market, 'leverage_max'),
                  },
                  'amount': {
                      'min': self.safe_number(market, 'order_size_min'),
                      'max': self.safe_number(market, 'order_size_max'),
                  },
                  'price': {
                      'min': self.parse_number(minPrice),
                      'max': self.parse_number(maxPrice),
                  },
                  'cost': {
                      'min': None,
                      'max': None,
                  },
              },
              'info': market,
          }
  
      def fetch_option_markets(self, params={}):
          result = []
          underlyings = self.fetch_option_underlyings()
          for i in range(0, len(underlyings)):
              underlying = underlyings[i]
              query = params
              query['underlying'] = underlying
              response = self.publicOptionsGetContracts(query)
              #
              #    [
              #        {
              #            "orders_limit": "50",
              #            "order_size_max": "100000",
              #            "mark_price_round": "0.1",
              #            "order_size_min": "1",
              #            "position_limit": "1000000",
              #            "orderbook_id": "575967",
              #            "order_price_deviate": "0.9",
              #            "is_call": True,  # True means Call False means Put
              #            "last_price": "93.9",
              #            "bid1_size": "0",
              #            "bid1_price": "0",
              #            "taker_fee_rate": "0.0004",
              #            "underlying": "BTC_USDT",
              #            "create_time": "1646381188",
              #            "price_limit_fee_rate": "0.1",
              #            "maker_fee_rate": "0.0004",
              #            "trade_id": "727",
              #            "order_price_round": "0.1",
              #            "settle_fee_rate": "0.0001",
              #            "trade_size": "1982",
              #            "ref_rebate_rate": "0",
              #            "name": "BTC_USDT-20220311-44000-C",
              #            "underlying_price": "39194.26",
              #            "strike_price": "44000",
              #            "multiplier": "0.0001",
              #            "ask1_price": "0",
              #            "ref_discount_rate": "0",
              #            "expiration_time": "1646985600",
              #            "mark_price": "12.15",
              #            "position_size": "4",
              #            "ask1_size": "0",
              #            "tag": "WEEK"
              #        }
              #    ]
              #
              for i in range(0, len(response)):
                  market = response[i]
                  id = self.safe_string(market, 'name')
                  parts = underlying.split('_')
                  baseId = self.safe_string(parts, 0)
                  quoteId = self.safe_string(parts, 1)
                  base = self.safe_currency_code(baseId)
                  quote = self.safe_currency_code(quoteId)
                  symbol = base + '/' + quote
                  expiry = self.safe_timestamp(market, 'expiration_time')
                  strike = self.safe_string(market, 'strike_price')
                  isCall = self.safe_value(market, 'is_call')
                  optionLetter = 'C' if isCall else 'P'
                  optionType = 'call' if isCall else 'put'
                  symbol = symbol + ':' + quote + '-' + self.yymmdd(expiry) + ':' + strike + ':' + optionLetter
                  priceDeviate = self.safe_string(market, 'order_price_deviate')
                  markPrice = self.safe_string(market, 'mark_price')
                  minMultiplier = Precise.string_sub('1', priceDeviate)
                  maxMultiplier = Precise.string_add('1', priceDeviate)
                  minPrice = Precise.string_mul(minMultiplier, markPrice)
                  maxPrice = Precise.string_mul(maxMultiplier, markPrice)
                  takerPercent = self.safe_string(market, 'taker_fee_rate')
                  makerPercent = self.safe_string(market, 'maker_fee_rate', takerPercent)
                  result.append({
                      'id': id,
                      'symbol': symbol,
                      'base': base,
                      'quote': quote,
                      'settle': quote,
                      'baseId': baseId,
                      'quoteId': quoteId,
                      'settleId': quoteId,
                      'type': 'option',
                      'spot': False,
                      'margin': False,
                      'swap': False,
                      'future': False,
                      'option': True,
                      'active': True,
                      'contract': True,
                      'linear': True,
                      'inverse': False,
                      'taker': self.parse_number(Precise.string_div(takerPercent, '100')),  # Fee is in %, so divide by 100
                      'maker': self.parse_number(Precise.string_div(makerPercent, '100')),
                      'contractSize': self.parse_number('1'),
                      'expiry': expiry,
                      'expiryDatetime': self.iso8601(expiry),
                      'strike': strike,
                      'optionType': optionType,
                      'precision': {
                          'amount': self.parse_number('1'),
                          'price': self.safe_number(market, 'order_price_round'),
                      },
                      'limits': {
                          'leverage': {
                              'min': None,
                              'max': None,
                          },
                          'amount': {
                              'min': self.safe_number(market, 'order_size_min'),
                              'max': self.safe_number(market, 'order_size_max'),
                          },
                          'price': {
                              'min': self.parse_number(minPrice),
                              'max': self.parse_number(maxPrice),
                          },
                          'cost': {
                              'min': None,
                              'max': None,
                          },
                      },
                      'info': market,
                  })
          return result
  
      def fetch_option_underlyings(self):
          underlyingsResponse = self.publicOptionsGetUnderlyings()
          #
          #    [
          #        {
          #            "index_time": "1646915796",
          #            "name": "BTC_USDT",
          #            "index_price": "39142.73"
          #        }
          #    ]
          #
          underlyings = []
          for i in range(0, len(underlyingsResponse)):
              underlying = underlyingsResponse[i]
              name = self.safe_string(underlying, 'name')
              if name is not None:
                  underlyings.append(name)
          return underlyings
  
      def prepare_request(self, market=None, type=None, params={}):
          """
           * @ignore
          Fills request params contract, settle, currency_pair, market and account where applicable
          :param dict market: CCXT market, required when type is None
          :param str type: 'spot', 'swap', or 'future', required when market is None
          :param dict params: request parameters
          :returns: the api request object, and the new params object with non-needed parameters removed
          """
          # * Do not call for multi spot order methods like cancelAllOrders and fetchOpenOrders. Use multiOrderSpotPrepareRequest instead
          request = {}
          if market is not None:
              if market['contract']:
                  request['contract'] = market['id']
                  request['settle'] = market['settleId']
              else:
                  request['currency_pair'] = market['id']
          else:
              swap = type == 'swap'
              future = type == 'future'
              if swap or future:
                  defaultSettle = 'usdt' if swap else 'btc'
                  settle = self.safe_string_lower(params, 'settle', defaultSettle)
                  params = self.omit(params, 'settle')
                  request['settle'] = settle
          return [request, params]
  
      def spot_order_prepare_request(self, market=None, stop=False, params={}):
          """
           * @ignore
          Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
          :param dict market: CCXT market
          :param bool stop: True if for a stop order
          :param dict params: request parameters
          :returns: the api request object, and the new params object with non-needed parameters removed
          """
          marginMode, query = self.get_margin_mode(stop, params)
          request = {}
          if not stop:
              if market is None:
                  raise ArgumentsRequired(self.id + ' spotOrderPrepareRequest() requires a market argument for non-stop orders')
              request['account'] = marginMode
              request['currency_pair'] = market['id']  # Should always be set for non-stop
          return [request, query]
  
      def multi_order_spot_prepare_request(self, market=None, stop=False, params={}):
          """
           * @ignore
          Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
          :param dict market: CCXT market
          :param bool stop: True if for a stop order
          :param dict params: request parameters
          :returns: the api request object, and the new params object with non-needed parameters removed
          """
          marginMode, query = self.get_margin_mode(stop, params)
          request = {
              'account': marginMode,
          }
          if market is not None:
              if stop:
                  # gateio spot and margin stop orders use the term market instead of currency_pair, and normal instead of spot. Neither parameter is used when fetching/cancelling a single order. They are used for creating a single stop order, but createOrder does not call self method
                  request['market'] = market['id']
              else:
                  request['currency_pair'] = market['id']
          return [request, query]
  
      def get_margin_mode(self, stop, params):
          """
           * @ignore
          Gets the margin type for self api call
          :param bool stop: True if for a stop order
          :param dict params: Request params
          :returns: The marginMode and the updated request params with marginMode removed, marginMode value is the value that can be read by the "account" property specified in gateios api docs
          """
          defaultMarginMode = self.safe_string_lower_2(self.options, 'defaultMarginMode', 'marginMode', 'spot')  # 'margin' is isolated margin on gateio's api
          marginMode = self.safe_string_lower_2(params, 'marginMode', 'account', defaultMarginMode)
          params = self.omit(params, ['marginMode', 'account'])
          if marginMode == 'cross':
              marginMode = 'cross_margin'
          elif marginMode == 'isolated':
              marginMode = 'margin'
          elif marginMode == '':
              marginMode = 'spot'
          if stop:
              if marginMode == 'spot':
                  # gateio spot stop orders use the term normal instead of spot
                  marginMode = 'normal'
              if marginMode == 'cross_margin':
                  raise BadRequest(self.id + ' getMarginMode() does not support stop orders for cross margin')
          return [marginMode, params]
  
      def get_settlement_currencies(self, type, method):
          options = self.safe_value(self.options, type, {})  # ['BTC', 'USDT'] unified codes
          fetchMarketsContractOptions = self.safe_value(options, method, {})
          defaultSettle = ['usdt'] if (type == 'swap') else ['btc']
          return self.safe_value(fetchMarketsContractOptions, 'settlementCurrencies', defaultSettle)
  
      def fetch_currencies(self, params={}):
          # sandbox/testnet only supports future markets
          apiBackup = self.safe_value(self.urls, 'apiBackup')
          if apiBackup is not None:
              return None
          response = self.publicSpotGetCurrencies(params)
          #
          #    {
          #        "currency": "BCN",
          #        "delisted": False,
          #        "withdraw_disabled": True,
          #        "withdraw_delayed": False,
          #        "deposit_disabled": True,
          #        "trade_disabled": False
          #    }
          #
          result = {}
          # TODO: remove magic constants
          amountPrecision = self.parse_number('1e-6')
          for i in range(0, len(response)):
              entry = response[i]
              currencyId = self.safe_string(entry, 'currency')
              currencyIdLower = self.safe_string_lower(entry, 'currency')
              code = self.safe_currency_code(currencyId)
              delisted = self.safe_value(entry, 'delisted')
              withdrawDisabled = self.safe_value(entry, 'withdraw_disabled', False)
              depositDisabled = self.safe_value(entry, 'deposit_disabled', False)
              tradeDisabled = self.safe_value(entry, 'trade_disabled', False)
              withdrawEnabled = not withdrawDisabled
              depositEnabled = not depositDisabled
              tradeEnabled = not tradeDisabled
              listed = not delisted
              active = listed and tradeEnabled and withdrawEnabled and depositEnabled
              result[code] = {
                  'id': currencyId,
                  'lowerCaseId': currencyIdLower,
                  'name': None,
                  'code': code,
                  'precision': amountPrecision,
                  'info': entry,
                  'active': active,
                  'deposit': depositEnabled,
                  'withdraw': withdrawEnabled,
                  'fee': None,
                  'fees': [],
                  'limits': self.limits,
              }
          return result
  
      def fetch_funding_rate(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          if not market['swap']:
              raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
          request, query = self.prepare_request(market, None, params)
          response = self.publicFuturesGetSettleContractsContract(self.extend(request, query))
          #
          #    [
          #        {
          #            "name": "BTC_USDT",
          #            "type": "direct",
          #            "quanto_multiplier": "0.0001",
          #            "ref_discount_rate": "0",
          #            "order_price_deviate": "0.5",
          #            "maintenance_rate": "0.005",
          #            "mark_type": "index",
          #            "last_price": "38026",
          #            "mark_price": "37985.6",
          #            "index_price": "37954.92",
          #            "funding_rate_indicative": "0.000219",
          #            "mark_price_round": "0.01",
          #            "funding_offset": 0,
          #            "in_delisting": False,
          #            "risk_limit_base": "1000000",
          #            "interest_rate": "0.0003",
          #            "order_price_round": "0.1",
          #            "order_size_min": 1,
          #            "ref_rebate_rate": "0.2",
          #            "funding_interval": 28800,
          #            "risk_limit_step": "1000000",
          #            "leverage_min": "1",
          #            "leverage_max": "100",
          #            "risk_limit_max": "8000000",
          #            "maker_fee_rate": "-0.00025",
          #            "taker_fee_rate": "0.00075",
          #            "funding_rate": "0.002053",
          #            "order_size_max": 1000000,
          #            "funding_next_apply": 1610035200,
          #            "short_users": 977,
          #            "config_change_time": 1609899548,
          #            "trade_size": 28530850594,
          #            "position_size": 5223816,
          #            "long_users": 455,
          #            "funding_impact_value": "60000",
          #            "orders_limit": 50,
          #            "trade_id": 10851092,
          #            "orderbook_id": 2129638396
          #        }
          #    ]
          #
          return self.parse_funding_rate(response)
  
      def fetch_funding_rates(self, symbols=None, params={}):
          self.load_markets()
          request, query = self.prepare_request(None, 'swap', params)
          response = self.publicFuturesGetSettleContracts(self.extend(request, query))
          #
          #    [
          #        {
          #            "name": "BTC_USDT",
          #            "type": "direct",
          #            "quanto_multiplier": "0.0001",
          #            "ref_discount_rate": "0",
          #            "order_price_deviate": "0.5",
          #            "maintenance_rate": "0.005",
          #            "mark_type": "index",
          #            "last_price": "38026",
          #            "mark_price": "37985.6",
          #            "index_price": "37954.92",
          #            "funding_rate_indicative": "0.000219",
          #            "mark_price_round": "0.01",
          #            "funding_offset": 0,
          #            "in_delisting": False,
          #            "risk_limit_base": "1000000",
          #            "interest_rate": "0.0003",
          #            "order_price_round": "0.1",
          #            "order_size_min": 1,
          #            "ref_rebate_rate": "0.2",
          #            "funding_interval": 28800,
          #            "risk_limit_step": "1000000",
          #            "leverage_min": "1",
          #            "leverage_max": "100",
          #            "risk_limit_max": "8000000",
          #            "maker_fee_rate": "-0.00025",
          #            "taker_fee_rate": "0.00075",
          #            "funding_rate": "0.002053",
          #            "order_size_max": 1000000,
          #            "funding_next_apply": 1610035200,
          #            "short_users": 977,
          #            "config_change_time": 1609899548,
          #            "trade_size": 28530850594,
          #            "position_size": 5223816,
          #            "long_users": 455,
          #            "funding_impact_value": "60000",
          #            "orders_limit": 50,
          #            "trade_id": 10851092,
          #            "orderbook_id": 2129638396
          #        }
          #    ]
          #
          result = self.parse_funding_rates(response)
          return self.filter_by_array(result, 'symbol', symbols)
  
      def parse_funding_rate(self, contract, market=None):
          #
          #    {
          #        "name": "BTC_USDT",
          #        "type": "direct",
          #        "quanto_multiplier": "0.0001",
          #        "ref_discount_rate": "0",
          #        "order_price_deviate": "0.5",
          #        "maintenance_rate": "0.005",
          #        "mark_type": "index",
          #        "last_price": "38026",
          #        "mark_price": "37985.6",
          #        "index_price": "37954.92",
          #        "funding_rate_indicative": "0.000219",
          #        "mark_price_round": "0.01",
          #        "funding_offset": 0,
          #        "in_delisting": False,
          #        "risk_limit_base": "1000000",
          #        "interest_rate": "0.0003",
          #        "order_price_round": "0.1",
          #        "order_size_min": 1,
          #        "ref_rebate_rate": "0.2",
          #        "funding_interval": 28800,
          #        "risk_limit_step": "1000000",
          #        "leverage_min": "1",
          #        "leverage_max": "100",
          #        "risk_limit_max": "8000000",
          #        "maker_fee_rate": "-0.00025",
          #        "taker_fee_rate": "0.00075",
          #        "funding_rate": "0.002053",
          #        "order_size_max": 1000000,
          #        "funding_next_apply": 1610035200,
          #        "short_users": 977,
          #        "config_change_time": 1609899548,
          #        "trade_size": 28530850594,
          #        "position_size": 5223816,
          #        "long_users": 455,
          #        "funding_impact_value": "60000",
          #        "orders_limit": 50,
          #        "trade_id": 10851092,
          #        "orderbook_id": 2129638396
          #    }
          #
          marketId = self.safe_string(contract, 'name')
          symbol = self.safe_symbol(marketId, market)
          markPrice = self.safe_number(contract, 'mark_price')
          indexPrice = self.safe_number(contract, 'index_price')
          interestRate = self.safe_number(contract, 'interest_rate')
          fundingRate = self.safe_number(contract, 'funding_rate')
          fundingTime = self.safe_integer(contract, 'funding_next_apply') * 1000
          fundingRateIndicative = self.safe_number(contract, 'funding_rate_indicative')
          return {
              'info': contract,
              'symbol': symbol,
              'markPrice': markPrice,
              'indexPrice': indexPrice,
              'interestRate': interestRate,
              'estimatedSettlePrice': None,
              'timestamp': None,
              'datetime': None,
              'fundingRate': fundingRate,
              'fundingTimestamp': fundingTime,
              'fundingDatetime': self.iso8601(fundingTime),
              'nextFundingRate': fundingRateIndicative,
              'nextFundingTimestamp': None,
              'nextFundingDatetime': None,
              'previousFundingRate': None,
              'previousFundingTimestamp': None,
              'previousFundingDatetime': None,
          }
  
      def fetch_network_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'currency': currency['id'],
          }
          response = self.privateWalletGetDepositAddress(self.extend(request, params))
          addresses = self.safe_value(response, 'multichain_addresses')
          currencyId = self.safe_string(response, 'currency')
          code = self.safe_currency_code(currencyId)
          result = {}
          for i in range(0, len(addresses)):
              entry = addresses[i]
              #
              #    {
              #        "chain": "ETH",
              #        "address": "0x359a697945E79C7e17b634675BD73B33324E9408",
              #        "payment_id": "",
              #        "payment_name": "",
              #        "obtain_failed": "0"
              #    }
              #
              obtainFailed = self.safe_integer(entry, 'obtain_failed')
              if obtainFailed:
                  continue
              network = self.safe_string(entry, 'chain')
              address = self.safe_string(entry, 'address')
              tag = self.safe_string(entry, 'payment_id')
              tagLength = len(tag)
              tag = tag if tagLength else None
              result[network] = {
                  'info': entry,
                  'code': code,
                  'address': address,
                  'tag': tag,
              }
          return result
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'currency': currency['id'],
          }
          response = self.privateWalletGetDepositAddress(self.extend(request, params))
          #
          #    {
          #        "currency": "XRP",
          #        "address": "rHcFoo6a9qT5NHiVn1THQRhsEGcxtYCV4d 391331007",
          #        "multichain_addresses": [
          #            {
          #                "chain": "XRP",
          #                "address": "rHcFoo6a9qT5NHiVn1THQRhsEGcxtYCV4d",
          #                "payment_id": "391331007",
          #                "payment_name": "Tag",
          #                "obtain_failed": 0
          #            }
          #        ]
          #    }
          #
          currencyId = self.safe_string(response, 'currency')
          code = self.safe_currency_code(currencyId)
          addressField = self.safe_string(response, 'address')
          tag = None
          address = None
          if addressField.find(' ') >= 0:
              splitted = addressField.split(' ')
              address = splitted[0]
              tag = splitted[1]
          else:
              address = addressField
          return {
              'info': response,
              'code': code,
              'address': address,
              'tag': tag,
              'network': None,
          }
  
      def fetch_trading_fee(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'currency_pair': market['id'],
          }
          response = self.privateWalletGetFee(self.extend(request, params))
          #
          #    {
          #        "user_id": 1486602,
          #        "taker_fee": "0.002",
          #        "maker_fee": "0.002",
          #        "gt_discount": True,
          #        "gt_taker_fee": "0.0015",
          #        "gt_maker_fee": "0.0015",
          #        "loan_fee": "0.18",
          #        "point_type": "0",
          #        "futures_taker_fee": "0.0005",
          #        "futures_maker_fee": "0"
          #    }
          #
          return self.parse_trading_fee(response, market)
  
      def fetch_trading_fees(self, params={}):
          self.load_markets()
          response = self.privateWalletGetFee(params)
          #
          #    {
          #        "user_id": 1486602,
          #        "taker_fee": "0.002",
          #        "maker_fee": "0.002",
          #        "gt_discount": True,
          #        "gt_taker_fee": "0.0015",
          #        "gt_maker_fee": "0.0015",
          #        "loan_fee": "0.18",
          #        "point_type": "0",
          #        "futures_taker_fee": "0.0005",
          #        "futures_maker_fee": "0"
          #    }
          #
          return self.parse_trading_fees(response)
  
      def parse_trading_fees(self, response):
          result = {}
          for i in range(0, len(self.symbols)):
              symbol = self.symbols[i]
              market = self.market(symbol)
              result[symbol] = self.parse_trading_fee(response, market)
          return result
  
      def parse_trading_fee(self, info, market=None):
          #
          #    {
          #        "user_id": 1486602,
          #        "taker_fee": "0.002",
          #        "maker_fee": "0.002",
          #        "gt_discount": True,
          #        "gt_taker_fee": "0.0015",
          #        "gt_maker_fee": "0.0015",
          #        "loan_fee": "0.18",
          #        "point_type": "0",
          #        "futures_taker_fee": "0.0005",
          #        "futures_maker_fee": "0"
          #    }
          #
          contract = self.safe_value(market, 'contract')
          takerKey = 'futures_taker_fee' if contract else 'taker_fee'
          makerKey = 'futures_maker_fee' if contract else 'maker_fee'
          return {
              'info': info,
              'symbol': self.safe_string(market, 'symbol'),
              'maker': self.safe_number(info, makerKey),
              'taker': self.safe_number(info, takerKey),
          }
  
      def fetch_transaction_fees(self, codes=None, params={}):
          self.load_markets()
          response = self.privateWalletGetWithdrawStatus(params)
          #
          #    {
          #        "currency": "MTN",
          #        "name": "Medicalchain",
          #        "name_cn": "Medicalchain",
          #        "deposit": "0",
          #        "withdraw_percent": "0%",
          #        "withdraw_fix": "900",
          #        "withdraw_day_limit": "500000",
          #        "withdraw_day_limit_remain": "500000",
          #        "withdraw_amount_mini": "900.1",
          #        "withdraw_eachtime_limit": "90000000000",
          #        "withdraw_fix_on_chains": {
          #            "ETH": "900"
          #        }
          #    }
          #
          withdrawFees = {}
          for i in range(0, len(response)):
              entry = response[i]
              currencyId = self.safe_string(entry, 'currency')
              code = self.safe_currency_code(currencyId)
              withdrawFees[code] = {}
              withdrawFix = self.safe_value(entry, 'withdraw_fix_on_chains')
              if withdrawFix is None:
                  withdrawFix = {}
                  withdrawFix[code] = self.safe_number(entry, 'withdraw_fix')
              keys = list(withdrawFix.keys())
              for i in range(0, len(keys)):
                  key = keys[i]
                  withdrawFees[code][key] = self.parse_number(withdrawFix[key])
          return {
              'info': response,
              'withdraw': withdrawFees,
              'deposit': {},
          }
  
      def fetch_funding_history(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          # defaultType = 'future'
          market = None
          if symbol is not None:
              market = self.market(symbol)
          type, query = self.handle_market_type_and_params('fetchFundingHistory', market, params)
          request, requestParams = self.prepare_request(market, type, query)
          request['type'] = 'fund'  # 'dnw' 'pnl' 'fee' 'refr' 'fund' 'point_dnw' 'point_fee' 'point_refr'
          if since is not None:
              request['from'] = since / 1000
          if limit is not None:
              request['limit'] = limit
          method = self.get_supported_mapping(type, {
              'swap': 'privateFuturesGetSettleAccountBook',
              'future': 'privateDeliveryGetSettleAccountBook',
          })
          response = getattr(self, method)(self.extend(request, requestParams))
          #
          #    [
          #        {
          #            "time": 1646899200,
          #            "change": "-0.027722",
          #            "balance": "11.653120591841",
          #            "text": "XRP_USDT",
          #            "type": "fund"
          #        },
          #        ...
          #    ]
          #
          return self.parse_funding_histories(response, symbol, since, limit)
  
      def parse_funding_histories(self, response, symbol, since, limit):
          result = []
          for i in range(0, len(response)):
              entry = response[i]
              funding = self.parse_funding_history(entry)
              result.append(funding)
          sorted = self.sort_by(result, 'timestamp')
          return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
  
      def parse_funding_history(self, info, market=None):
          #
          #    {
          #        "time": 1646899200,
          #        "change": "-0.027722",
          #        "balance": "11.653120591841",
          #        "text": "XRP_USDT",
          #        "type": "fund"
          #    }
          #
          timestamp = self.safe_timestamp(info, 'time')
          marketId = self.safe_string(info, 'text')
          market = self.safe_market(marketId, market)
          return {
              'info': info,
              'symbol': self.safe_string(market, 'symbol'),
              'code': self.safe_string(market, 'settle'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'id': None,
              'amount': self.safe_number(info, 'change'),
          }
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          #
          #     request = {
          #         'currency_pair': market['id'],
          #         'interval': '0',  # depth, 0 means no aggregation is applied, default to 0
          #         'limit': limit,  # maximum number of order depth data in asks or bids
          #         'with_id': True,  # return order book ID
          #     }
          #
          request, query = self.prepare_request(market, None, params)
          method = self.get_supported_mapping(market['type'], {
              'spot': 'publicSpotGetOrderBook',
              'margin': 'publicSpotGetOrderBook',
              'swap': 'publicFuturesGetSettleOrderBook',
              'future': 'publicDeliveryGetSettleOrderBook',
          })
          if limit is not None:
              request['limit'] = limit  # default 10, max 100
          request['with_id'] = True
          response = getattr(self, method)(self.extend(request, query))
          #
          # SPOT
          #
          #     {
          #         "id": 6358770031
          #         "current": 1634345973275,
          #         "update": 1634345973271,
          #         "asks": [
          #             ["2.2241","12449.827"],
          #             ["2.2242","200"],
          #             ["2.2244","826.931"],
          #             ["2.2248","3876.107"],
          #             ["2.225","2377.252"],
          #             ["2.22509","439.484"],
          #             ["2.2251","1489.313"],
          #             ["2.2253","714.582"],
          #             ["2.2254","1349.784"],
          #             ["2.2256","234.701"]],
          #          "bids": [
          #             ["2.2236","32.465"],
          #             ["2.2232","243.983"],
          #             ["2.2231","32.207"],
          #             ["2.223","449.827"],
          #             ["2.2228","7.918"],
          #             ["2.2227","12703.482"],
          #             ["2.2226","143.033"],
          #             ["2.2225","143.027"],
          #             ["2.2224","1369.352"],
          #             ["2.2223","756.063"]
          #         ]
          #     }
          #
          # Perpetual Swap
          #
          #     {
          #         "id": 6358770031
          #         "current": 1634350208.745,
          #         "asks": [
          #             {"s": 24909, "p": "61264.8"},
          #             {"s": 81, "p": "61266.6"},
          #             {"s": 2000, "p": "61267.6"},
          #             {"s": 490, "p": "61270.2"},
          #             {"s": 12, "p": "61270.4"},
          #             {"s": 11782, "p": "61273.2"},
          #             {"s": 14666, "p": "61273.3"},
          #             {"s": 22541, "p": "61273.4"},
          #             {"s": 33, "p": "61273.6"},
          #             {"s": 11980, "p": "61274.5"}
          #         ],
          #         "bids": [
          #             {"s": 41844, "p": "61264.7"},
          #             {"s": 13783, "p": "61263.3"},
          #             {"s": 1143, "p": "61259.8"},
          #             {"s": 81, "p": "61258.7"},
          #             {"s": 2471, "p": "61257.8"},
          #             {"s": 2471, "p": "61257.7"},
          #             {"s": 2471, "p": "61256.5"},
          #             {"s": 3, "p": "61254.2"},
          #             {"s": 114, "p": "61252.4"},
          #             {"s": 14372, "p": "61248.6"}
          #         ],
          #         "update": 1634350208.724
          #     }
          #
          timestamp = self.safe_integer(response, 'current')
          if not market['spot']:
              timestamp = timestamp * 1000
          priceKey = 0 if market['spot'] else 'p'
          amountKey = 1 if market['spot'] else 's'
          nonce = self.safe_integer(response, 'id')
          result = self.parse_order_book(response, symbol, timestamp, 'bids', 'asks', priceKey, amountKey)
          result['nonce'] = nonce
          return result
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request, query = self.prepare_request(market, None, params)
          method = self.get_supported_mapping(market['type'], {
              'spot': 'publicSpotGetTickers',
              'margin': 'publicSpotGetTickers',
              'swap': 'publicFuturesGetSettleTickers',
              'future': 'publicDeliveryGetSettleTickers',
          })
          response = getattr(self, method)(self.extend(request, query))
          ticker = self.safe_value(response, 0)
          return self.parse_ticker(ticker, market)
  
      def parse_ticker(self, ticker, market=None):
          #
          # SPOT
          #
          #     {
          #         "currency_pair": "KFC_USDT",
          #         "last": "7.255",
          #         "lowest_ask": "7.298",
          #         "highest_bid": "7.218",
          #         "change_percentage": "-1.18",
          #         "base_volume": "1219.053687865",
          #         "quote_volume": "8807.40299875455",
          #         "high_24h": "7.262",
          #         "low_24h": "7.095"
          #     }
          #
          # LINEAR/DELIVERY
          #
          #     {
          #         "contract": "BTC_USDT",
          #         "last": "6432",
          #         "low_24h": "6278",
          #         "high_24h": "6790",
          #         "change_percentage": "4.43",
          #         "total_size": "32323904",
          #         "volume_24h": "184040233284",
          #         "volume_24h_btc": "28613220",
          #         "volume_24h_usd": "184040233284",
          #         "volume_24h_base": "28613220",
          #         "volume_24h_quote": "184040233284",
          #         "volume_24h_settle": "28613220",
          #         "mark_price": "6534",
          #         "funding_rate": "0.0001",
          #         "funding_rate_indicative": "0.0001",
          #         "index_price": "6531"
          #     }
          #
          marketId = self.safe_string_2(ticker, 'currency_pair', 'contract')
          symbol = self.safe_symbol(marketId, market)
          last = self.safe_string(ticker, 'last')
          ask = self.safe_string(ticker, 'lowest_ask')
          bid = self.safe_string(ticker, 'highest_bid')
          high = self.safe_string(ticker, 'high_24h')
          low = self.safe_string(ticker, 'low_24h')
          baseVolume = self.safe_string_2(ticker, 'base_volume', 'volume_24h_base')
          quoteVolume = self.safe_string_2(ticker, 'quote_volume', 'volume_24h_quote')
          percentage = self.safe_string(ticker, 'change_percentage')
          return self.safe_ticker({
              'symbol': symbol,
              'timestamp': None,
              'datetime': None,
              'high': high,
              'low': low,
              'bid': bid,
              'bidVolume': None,
              'ask': ask,
              'askVolume': None,
              'vwap': None,
              'open': None,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': None,
              'percentage': percentage,
              'average': None,
              'baseVolume': baseVolume,
              'quoteVolume': quoteVolume,
              'info': ticker,
          }, market, False)
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          type, query = self.handle_market_type_and_params('fetchTickers', None, params)
          request, requestParams = self.prepare_request(None, type, query)
          method = self.get_supported_mapping(type, {
              'spot': 'publicSpotGetTickers',
              'margin': 'publicSpotGetTickers',
              'swap': 'publicFuturesGetSettleTickers',
              'future': 'publicDeliveryGetSettleTickers',
          })
          response = getattr(self, method)(self.extend(request, requestParams))
          return self.parse_tickers(response, symbols)
  
      def fetch_balance_helper(self, entry):
          account = self.account()
          account['used'] = self.safe_string_2(entry, 'freeze', 'locked')
          account['free'] = self.safe_string(entry, 'available')
          account['total'] = self.safe_string(entry, 'total')
          return account
  
      def fetch_balance(self, params={}):
          """
          :param dict params: exchange specific parameters
          :param str params['type']: spot, margin, swap or future, if not provided self.options['defaultType'] is used
          :param str params['settle']: 'btc' or 'usdt' - settle currency for perpetual swap and future - default="usdt" for swap and "btc" for future
          :param str params['marginMode']: 'cross' or 'isolated' - marginMode for margin trading if not provided self.options['defaultMarginMode'] is used
          :param str params['symbol']: margin only - unified ccxt symbol
          """
          self.load_markets()
          symbol = self.safe_string(params, 'symbol')
          params = self.omit(params, 'symbol')
          type, query = self.handle_market_type_and_params('fetchBalance', None, params)
          request, requestParams = self.prepare_request(None, type, query)
          marginMode, requestQuery = self.get_margin_mode(False, requestParams)
          if symbol is not None:
              market = self.market(symbol)
              request['currency_pair'] = market['id']
          method = self.get_supported_mapping(type, {
              'spot': self.get_supported_mapping(marginMode, {
                  'spot': 'privateSpotGetAccounts',
                  'margin': 'privateMarginGetAccounts',
                  'cross_margin': 'privateMarginGetCrossAccounts',
              }),
              'funding': 'privateMarginGetFundingAccounts',
              'swap': 'privateFuturesGetSettleAccounts',
              'future': 'privateDeliveryGetSettleAccounts',
          })
          response = getattr(self, method)(self.extend(request, requestQuery))
          contract = (type == 'swap' or type == 'future')
          if contract:
              response = [response]
          #
          # Spot / margin funding
          #
          #     [
          #         {
          #             "currency": "DBC",
          #             "available": "0",
          #             "locked": "0"
          #             "lent": "0",  # margin funding only
          #             "total_lent": "0"  # margin funding only
          #         },
          #         ...
          #     ]
          #
          #  Margin
          #
          #    [
          #        {
          #            "currency_pair": "DOGE_USDT",
          #            "locked": False,
          #            "risk": "9999.99",
          #            "base": {
          #                "currency": "DOGE",
          #                "available": "0",
          #                "locked": "0",
          #                "borrowed": "0",
          #                "interest": "0"
          #            },
          #            "quote": {
          #                "currency": "USDT",
          #                "available": "0.73402",
          #                "locked": "0",
          #                "borrowed": "0",
          #                "interest": "0"
          #            }
          #        },
          #        ...
          #    ]
          #
          # Cross margin
          #
          #    {
          #        "user_id": 10406147,
          #        "locked": False,
          #        "balances": {
          #            "USDT": {
          #                "available": "1",
          #                "freeze": "0",
          #                "borrowed": "0",
          #                "interest": "0"
          #            }
          #        },
          #        "total": "1",
          #        "borrowed": "0",
          #        "interest": "0",
          #        "risk": "9999.99"
          #    }
          #
          #  Perpetual Swap
          #
          #    {
          #        order_margin: "0",
          #        point: "0",
          #        bonus: "0",
          #        history: {
          #            dnw: "2.1321",
          #            pnl: "11.5351",
          #            refr: "0",
          #            point_fee: "0",
          #            fund: "-0.32340576684",
          #            bonus_dnw: "0",
          #            point_refr: "0",
          #            bonus_offset: "0",
          #            fee: "-0.20132775",
          #            point_dnw: "0",
          #        },
          #        unrealised_pnl: "13.315100000006",
          #        total: "12.51345151332",
          #        available: "0",
          #        in_dual_mode: False,
          #        currency: "USDT",
          #        position_margin: "12.51345151332",
          #        user: "6333333",
          #    }
          #
          # Delivery Future
          #
          #    {
          #        order_margin: "0",
          #        point: "0",
          #        history: {
          #            dnw: "1",
          #            pnl: "0",
          #            refr: "0",
          #            point_fee: "0",
          #            point_dnw: "0",
          #            settle: "0",
          #            settle_fee: "0",
          #            point_refr: "0",
          #            fee: "0",
          #        },
          #        unrealised_pnl: "0",
          #        total: "1",
          #        available: "1",
          #        currency: "USDT",
          #        position_margin: "0",
          #        user: "6333333",
          #    }
          #
          result = {
              'info': response,
          }
          crossMargin = marginMode == 'cross_margin'
          margin = marginMode == 'margin'
          data = response
          if 'balances' in data:  # True for cross_margin
              flatBalances = []
              balances = self.safe_value(data, 'balances', [])
              # inject currency and create an artificial balance object
              # so it can follow the existent flow
              keys = list(balances.keys())
              for i in range(0, len(keys)):
                  currencyId = keys[i]
                  content = balances[currencyId]
                  content['currency'] = currencyId
                  flatBalances.append(content)
              data = flatBalances
          for i in range(0, len(data)):
              entry = data[i]
              if margin and not crossMargin:
                  marketId = self.safe_string(entry, 'currency_pair')
                  symbol = self.safe_symbol(marketId, None, '_')
                  base = self.safe_value(entry, 'base', {})
                  quote = self.safe_value(entry, 'quote', {})
                  baseCode = self.safe_currency_code(self.safe_string(base, 'currency', {}))
                  quoteCode = self.safe_currency_code(self.safe_string(quote, 'currency', {}))
                  subResult = {}
                  subResult[baseCode] = self.fetch_balance_helper(base)
                  subResult[quoteCode] = self.fetch_balance_helper(quote)
                  result[symbol] = self.safe_balance(subResult)
              else:
                  code = self.safe_currency_code(self.safe_string(entry, 'currency', {}))
                  result[code] = self.fetch_balance_helper(entry)
          return result if (margin and not crossMargin) else self.safe_balance(result)
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          price = self.safe_string(params, 'price')
          request = {}
          request, params = self.prepare_request(market, None, params)
          request['interval'] = self.timeframes[timeframe]
          method = 'publicSpotGetCandlesticks'
          maxLimit = 1000
          if market['contract']:
              maxLimit = 1999
              limit = maxLimit if (limit is None) else min(limit, maxLimit)
              if market['future']:
                  method = 'publicDeliveryGetSettleCandlesticks'
              elif market['swap']:
                  method = 'publicFuturesGetSettleCandlesticks'
              isMark = (price == 'mark')
              isIndex = (price == 'index')
              if isMark or isIndex:
                  request['contract'] = price + '_' + market['id']
                  params = self.omit(params, 'price')
          limit = maxLimit if (limit is None) else min(limit, maxLimit)
          if since is not None:
              duration = self.parse_timeframe(timeframe)
              request['from'] = int(since / 1000)
              toTimestamp = self.sum(request['from'], limit * duration - 1)
              currentTimestamp = self.seconds()
              request['to'] = min(toTimestamp, currentTimestamp)
          else:
              request['limit'] = limit
          response = getattr(self, method)(self.extend(request, params))
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      def fetch_mark_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          request = {
              'price': 'mark',
          }
          return self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params))
  
      def fetch_funding_rate_history(self, symbol=None, since=None, limit=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          if not market['swap']:
              raise BadSymbol(self.id + ' fetchFundingRateHistory() supports swap contracts only')
          request, query = self.prepare_request(market, None, params)
          if limit is not None:
              request['limit'] = limit
          method = 'publicFuturesGetSettleFundingRate'
          response = getattr(self, method)(self.extend(request, query))
          #
          #     {
          #         "r": "0.00063521",
          #         "t": "1621267200000",
          #     }
          #
          rates = []
          for i in range(0, len(response)):
              entry = response[i]
              timestamp = self.safe_timestamp(entry, 't')
              rates.append({
                  'info': entry,
                  'symbol': symbol,
                  'fundingRate': self.safe_number(entry, 'r'),
                  'timestamp': timestamp,
                  'datetime': self.iso8601(timestamp),
              })
          sorted = self.sort_by(rates, 'timestamp')
          return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
  
      def fetch_index_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          request = {
              'price': 'index',
          }
          return self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params))
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          # Spot market candles
          #
          #     [
          #         "1626163200",           # Unix timestamp in seconds
          #         "346711.933138181617",  # Trading volume
          #         "33165.23",             # Close price
          #         "33260",                # Highest price
          #         "33117.6",              # Lowest price
          #         "33184.47"              # Open price
          #     ]
          #
          # Mark and Index price candles
          #
          #     {
          #          "t":1632873600,         # Unix timestamp in seconds
          #          "o": "41025",           # Open price
          #          "h": "41882.17",        # Highest price
          #          "c": "41776.92",        # Close price
          #          "l": "40783.94"         # Lowest price
          #     }
          #
          if isinstance(ohlcv, list):
              return [
                  self.safe_timestamp(ohlcv, 0),   # unix timestamp in seconds
                  self.safe_number(ohlcv, 5),      # open price
                  self.safe_number(ohlcv, 3),      # highest price
                  self.safe_number(ohlcv, 4),      # lowest price
                  self.safe_number(ohlcv, 2),      # close price
                  self.safe_number(ohlcv, 1),      # trading volume
              ]
          else:
              # Mark and Index price candles
              return [
                  self.safe_timestamp(ohlcv, 't'),  # unix timestamp in seconds
                  self.safe_number(ohlcv, 'o'),    # open price
                  self.safe_number(ohlcv, 'h'),    # highest price
                  self.safe_number(ohlcv, 'l'),    # lowest price
                  self.safe_number(ohlcv, 'c'),    # close price
                  self.safe_number(ohlcv, 'v'),    # trading volume, None for mark or index price
              ]
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          #
          # spot
          #
          #     request = {
          #         'currency_pair': market['id'],
          #         'limit': limit,  # maximum number of records to be returned in a single list
          #         'last_id': 'id',  # specify list staring point using the id of last record in previous list-query results
          #         'reverse': False,  # True to retrieve records where id is smaller than the specified last_id, False to retrieve records where id is larger than the specified last_id
          #     }
          #
          # swap, future
          #
          #     request = {
          #         'settle': market['settleId'],
          #         'contract': market['id'],
          #         'limit': limit,  # maximum number of records to be returned in a single list
          #         'last_id': 'id',  # specify list staring point using the id of last record in previous list-query results
          #         'from': since / 1000),  # starting time in seconds, if not specified, to and limit will be used to limit response items
          #         'to': self.seconds(),  # end time in seconds, default to current time
          #     }
          #
          request, query = self.prepare_request(market, None, params)
          method = self.get_supported_mapping(market['type'], {
              'spot': 'publicSpotGetTrades',
              'margin': 'publicSpotGetTrades',
              'swap': 'publicFuturesGetSettleTrades',
              'future': 'publicDeliveryGetSettleTrades',
          })
          if limit is not None:
              request['limit'] = limit  # default 100, max 1000
          if since is not None and (market['contract']):
              request['from'] = int(since / 1000)
          response = getattr(self, method)(self.extend(request, query))
          #
          # spot
          #
          #     [
          #         {
          #             id: "1852958144",
          #             create_time: "1634673259",
          #             create_time_ms: "1634673259378.105000",
          #             currency_pair: "ADA_USDT",
          #             side: "sell",
          #             amount: "307.078",
          #             price: "2.104",
          #         }
          #     ]
          #
          # perpetual swap
          #
          #     [
          #         {
          #              size: "2",
          #              id: "2522911",
          #              create_time_ms: "1634673380.182",
          #              create_time: "1634673380.182",
          #              contract: "ADA_USDT",
          #              price: "2.10486",
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          """
          Fetch personal trading history
          :param str symbol: The symbol for the market to fetch trades for
          :param int since: The earliest timestamp, in ms, that fetched trades were made
          :param int limit: The max number of trades to fetch
          :param dict params: Exchange specific parameters
          :param str params['marginMode']: 'cross' or 'isolated' - marginMode for margin trading if not provided self.options['defaultMarginMode'] is used
          :param str params['type']: 'spot', 'swap', or 'future', if not provided self.options['defaultMarginMode'] is used
          :param int params['till']: The latest timestamp, in ms, that fetched trades were made
          :param int params['page']: *spot only* Page number
          :param str params['order_id']: *spot only* Filter trades with specified order ID. symbol is also required if self field is present
          :param str params['order']: *contract only* Futures order ID, return related data only if specified
          :param int params['offset']: *contract only* list offset, starting from 0
          :param str params['last_id']: *contract only* specify list staring point using the id of last record in previous list-query results
          :param int params['count_total']: *contract only* whether to return total number matched, default to 0(no return)
          :returns: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
          """
          self.load_markets()
          type = None
          marginMode = None
          request = {}
          market = self.market(symbol) if (symbol is not None) else None
          till = self.safe_number(params, 'till')
          params = self.omit(params, 'till')
          type, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
          contract = (type == 'swap') or (type == 'future')
          if contract:
              request, params = self.prepare_request(market, type, params)
          else:
              if market is not None:
                  request['currency_pair'] = market['id']  # Should always be set for non-stop
              marginMode, params = self.get_margin_mode(False, params)
              request['account'] = marginMode
          if limit is not None:
              request['limit'] = limit  # default 100, max 1000
          if since is not None:
              request['from'] = int(since / 1000)
          if till is not None:
              request['to'] = int(till / 1000)
          method = self.get_supported_mapping(type, {
              'spot': 'privateSpotGetMyTrades',
              'margin': 'privateSpotGetMyTrades',
              'swap': 'privateFuturesGetSettleMyTrades',
              'future': 'privateDeliveryGetSettleMyTrades',
          })
          response = getattr(self, method)(self.extend(request, params))
          #
          # spot
          #
          #     [
          #         {
          #             "id": "2876130500",
          #             "create_time": "1645464610",
          #             "create_time_ms": "1645464610777.399200",
          #             "currency_pair": "DOGE_USDT",
          #             "side": "sell",
          #             "role": "taker",
          #             "amount": "10.97",
          #             "price": "0.137384",
          #             "order_id": "125924049993",
          #             "fee": "0.00301420496",
          #             "fee_currency": "USDT",
          #             "point_fee": "0",
          #             "gt_fee": "0"
          #         }
          #     ]
          #
          # perpetual swap
          #
          #     [
          #         {
          #             "size": -5,
          #             "order_id": "130264979823",
          #             "id": 26884791,
          #             "role": "taker",
          #             "create_time": 1645465199.5472,
          #             "contract": "DOGE_USDT",
          #             "price": "0.136888"
          #         }
          #     ]
          #
          # future
          #
          #     [
          #         {
          #             "id": 121234231,
          #             "create_time": 1514764800.123,
          #             "contract": "BTC_USDT",
          #             "order_id": "21893289839",
          #             "size": 100,
          #             "price": "100.123",
          #             "role": "taker"
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def parse_trade(self, trade, market=None):
          #
          # public
          #
          #     {
          #         "id": "1334253759",
          #         "create_time": "1626342738",
          #         "create_time_ms": "1626342738331.497000",
          #         "currency_pair": "BTC_USDT",
          #         "side": "sell",
          #         "amount": "0.0022",
          #         "price": "32452.16"
          #     }
          #
          # public ws
          #
          #     {
          #         id: 221994511,
          #         time: 1580311438.618647,
          #         price: '9309',
          #         amount: '0.0019',
          #         type: 'sell'
          #     }
          #
          # spot rest
          #
          #     {
          #         "id": "2876130500",
          #         "create_time": "1645464610",
          #         "create_time_ms": "1645464610777.399200",
          #         "currency_pair": "DOGE_USDT",
          #         "side": "sell",
          #         "role": "taker",
          #         "amount": "10.97",
          #         "price": "0.137384",
          #         "order_id": "125924049993",
          #         "fee": "0.00301420496",
          #         "fee_currency": "USDT",
          #         "point_fee": "0","gt_fee":"0"
          #     }
          #
          # perpetual swap rest
          #
          #     {
          #         "size": -5,
          #         "order_id": "130264979823",
          #         "id": 26884791,
          #         "role": "taker",
          #         "create_time": 1645465199.5472,
          #         "contract": "DOGE_USDT",
          #         "price": "0.136888"
          #     }
          #
          # future rest
          #
          #     {
          #         "id": 121234231,
          #         "create_time": 1514764800.123,
          #         "contract": "BTC_USDT",
          #         "order_id": "21893289839",
          #         "size": 100,
          #         "price": "100.123",
          #         "role": "taker"
          #     }
          #
          id = self.safe_string(trade, 'id')
          timestamp = self.safe_timestamp_2(trade, 'time', 'create_time')
          timestamp = self.safe_integer(trade, 'create_time_ms', timestamp)
          marketId = self.safe_string_2(trade, 'currency_pair', 'contract')
          symbol = self.safe_symbol(marketId, market)
          amountString = self.safe_string_2(trade, 'amount', 'size')
          priceString = self.safe_string(trade, 'price')
          contractSide = 'sell' if Precise.string_lt(amountString, '0') else 'buy'
          amountString = Precise.string_abs(amountString)
          side = self.safe_string_2(trade, 'side', 'type', contractSide)
          orderId = self.safe_string(trade, 'order_id')
          gtFee = self.safe_string(trade, 'gt_fee')
          feeCurrency = None
          feeCostString = None
          if gtFee == '0':
              feeCurrency = self.safe_string(trade, 'fee_currency')
              feeCostString = self.safe_string(trade, 'fee')
          else:
              feeCurrency = 'GT'
              feeCostString = gtFee
          fee = {
              'cost': feeCostString,
              'currency': feeCurrency,
          }
          takerOrMaker = self.safe_string(trade, 'role')
          return self.safe_trade({
              'info': trade,
              'id': id,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'order': orderId,
              'type': None,
              'side': side,
              'takerOrMaker': takerOrMaker,
              'price': priceString,
              'amount': amountString,
              'cost': None,
              'fee': fee,
          }, market)
  
      def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['currency'] = currency['id']
          if limit is not None:
              request['limit'] = limit
          if since is not None:
              start = int(since / 1000)
              request['from'] = start
              request['to'] = self.sum(start, 30 * 24 * 60 * 60)
          response = self.privateWalletGetDeposits(self.extend(request, params))
          return self.parse_transactions(response, currency)
  
      def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['currency'] = currency['id']
          if limit is not None:
              request['limit'] = limit
          if since is not None:
              start = int(since / 1000)
              request['from'] = start
              request['to'] = self.sum(start, 30 * 24 * 60 * 60)
          response = self.privateWalletGetWithdrawals(self.extend(request, params))
          return self.parse_transactions(response, currency)
  
      def withdraw(self, code, amount, address, tag=None, params={}):
          tag, params = self.handle_withdraw_tag_and_params(tag, params)
          self.check_address(address)
          self.load_markets()
          currency = self.currency(code)
          request = {
              'currency': currency['id'],
              'address': address,
              'amount': self.currency_to_precision(code, amount),
          }
          if tag is not None:
              request['memo'] = tag
          networks = self.safe_value(self.options, 'networks', {})
          network = self.safe_string_upper(params, 'network')  # self line allows the user to specify either ERC20 or ETH
          network = self.safe_string_lower(networks, network, network)  # handle ETH>ERC20 alias
          if network is not None:
              request['chain'] = network
              params = self.omit(params, 'network')
          response = self.privateWithdrawalsPost(self.extend(request, params))
          #
          #    {
          #        "id": "w13389675",
          #        "currency": "USDT",
          #        "amount": "50",
          #        "address": "TUu2rLFrmzUodiWfYki7QCNtv1akL682p1",
          #        "memo": null
          #    }
          #
          return self.parse_transaction(response, currency)
  
      def parse_transaction_status(self, status):
          statuses = {
              'PEND': 'pending',
              'REQUEST': 'pending',
              'DMOVE': 'pending',
              'CANCEL': 'failed',
              'DONE': 'ok',
              'BCODE': 'ok',  # GateCode withdrawal
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction_type(self, type):
          types = {
              'd': 'deposit',
              'w': 'withdrawal',
          }
          return self.safe_string(types, type, type)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # deposits
          #
          #    {
          #        "id": "d33361395",
          #        "currency": "USDT_TRX",
          #        "address": "TErdnxenuLtXfnMafLbfappYdHtnXQ5U4z",
          #        "amount": "100",
          #        "txid": "ae9374de34e558562fe18cbb1bf9ab4d9eb8aa7669d65541c9fa2a532c1474a0",
          #        "timestamp": "1626345819",
          #        "status": "DONE",
          #        "memo": ""
          #    }
          #
          # withdraw
          #
          #    {
          #        "id": "w13389675",
          #        "currency": "USDT",
          #        "amount": "50",
          #        "address": "TUu2rLFrmzUodiWfYki7QCNtv1akL682p1",
          #        "memo": null
          #    }
          #
          id = self.safe_string(transaction, 'id')
          type = None
          amount = self.safe_string(transaction, 'amount')
          if id[0] == 'b':
              # GateCode handling
              type = 'deposit' if Precise.string_gt(amount, '0') else 'withdrawal'
              amount = Precise.string_abs(amount)
          elif id is not None:
              type = self.parse_transaction_type(id[0])
          currencyId = self.safe_string(transaction, 'currency')
          code = self.safe_currency_code(currencyId)
          txid = self.safe_string(transaction, 'txid')
          rawStatus = self.safe_string(transaction, 'status')
          status = self.parse_transaction_status(rawStatus)
          address = self.safe_string(transaction, 'address')
          fee = self.safe_number(transaction, 'fee')
          tag = self.safe_string(transaction, 'memo')
          if tag == '':
              tag = None
          timestamp = self.safe_timestamp(transaction, 'timestamp')
          return {
              'info': transaction,
              'id': id,
              'txid': txid,
              'currency': code,
              'amount': self.parse_number(amount),
              'network': None,
              'address': address,
              'addressTo': None,
              'addressFrom': None,
              'tag': tag,
              'tagTo': None,
              'tagFrom': None,
              'status': status,
              'type': type,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'updated': None,
              'fee': fee,
          }
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          """
          Create an order on the exchange
          :param str symbol: Unified CCXT market symbol
          :param str type: "limit" or "market" *"market" is contract only*
          :param str side: "buy" or "sell"
          :param float amount: the amount of currency to trade
          :param float price: *ignored in "market" orders* the price at which the order is to be fullfilled at in units of the quote currency
          :param dict params:  Extra parameters specific to the exchange API endpoint
          :param float params['stopPrice']: The price at which a trigger order is triggered at
          :param str params['timeInForce']: "GTC", "IOC", or "PO"
          :param str params['marginMode']: 'cross' or 'isolated' - marginMode for margin trading if not provided self.options['defaultMarginMode'] is used
          :param int params['iceberg']: Amount to display for the iceberg order, Null or 0 for normal orders, Set to -1 to hide the order completely
          :param str params['text']: User defined information
          :param str params['account']: *spot and margin only* "spot", "margin" or "cross_margin"
          :param bool params['auto_borrow']: *margin only* Used in margin or cross margin trading to allow automatic loan of insufficient amount if balance is not enough
          :param str params['settle']: *contract only* Unified Currency Code for settle currency
          :param bool params['reduceOnly']: *contract only* Indicates if self order is to reduce the size of a position
          :param bool params['close']: *contract only* Set as True to close the position, with size set to 0
          :param bool params['auto_size']: *contract only* Set side to close dual-mode position, close_long closes the long side, while close_short the short one, size also needs to be set to 0
          :returns: `An order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
          """
          self.load_markets()
          market = self.market(symbol)
          contract = market['contract']
          stopPrice = self.safe_number(params, 'stopPrice')
          methodTail = 'Orders'
          reduceOnly = self.safe_value_2(params, 'reduce_only', 'reduceOnly')
          defaultTimeInForce = self.safe_value_2(params, 'tif', 'time_in_force', 'gtc')
          timeInForce = self.safe_value(params, 'timeInForce', defaultTimeInForce)
          postOnly = False
          type, postOnly, timeInForce, params = self.is_post_only(type, timeInForce, None, params)
          params = self.omit(params, ['stopPrice', 'reduce_only', 'reduceOnly', 'tif', 'time_in_force', 'timeInForce'])
          if postOnly:
              timeInForce = 'poc'
          isLimitOrder = (type == 'limit')
          isMarketOrder = (type == 'market')
          if isLimitOrder and price is None:
              raise ArgumentsRequired(self.id + ' createOrder() requires a price argument for ' + type + ' orders')
          if contract:
              amountToPrecision = self.amount_to_precision(symbol, amount)
              signedAmount = Precise.string_neg(amountToPrecision) if (side == 'sell') else amountToPrecision
              amount = int(signedAmount)
              if isMarketOrder:
                  timeInForce = 'ioc'
                  price = 0
          elif not isLimitOrder:
              # Gateio doesn't have market orders for spot
              raise InvalidOrder(self.id + ' createOrder() does not support ' + type + ' orders for ' + market['type'] + ' markets')
          request = None
          trigger = self.safe_value(params, 'trigger')
          if stopPrice is None and trigger is None:
              if contract:
                  # contract order
                  request = {
                      'contract': market['id'],  # filled in prepareRequest above
                      'size': amount,  # int64, positive = bid, negative = ask
                      # 'iceberg': 0,  # int64, display size for iceberg order, 0 for non-iceberg, note that you will have to pay the taker fee for the hidden size
                      'price': self.price_to_precision(symbol, price),  # 0 for market order with tif set as ioc
                      # 'close': False,  # True to close the position, with size set to 0
                      # 'reduce_only': False,  # St as True to be reduce-only order
                      # 'tif': 'gtc',  # gtc, ioc, poc PendingOrCancelled == postOnly order
                      # 'text': clientOrderId,  # 't-abcdef1234567890',
                      # 'auto_size': '',  # close_long, close_short, note size also needs to be set to 0
                      'settle': market['settleId'],  # filled in prepareRequest above
                  }
                  if reduceOnly is not None:
                      request['reduce_only'] = reduceOnly
                  if timeInForce is not None:
                      request['tif'] = timeInForce
              else:
                  marginMode = None
                  marginMode, params = self.get_margin_mode(False, params)
                  # spot order
                  request = {
                      # 'text': clientOrderId,  # 't-abcdef1234567890',
                      'currency_pair': market['id'],  # filled in prepareRequest above
                      'type': type,
                      'account': marginMode,  # 'spot', 'margin', 'cross_margin'
                      'side': side,
                      'amount': self.amount_to_precision(symbol, amount),
                      'price': self.price_to_precision(symbol, price),
                      # 'time_in_force': 'gtc',  # gtc, ioc, poc PendingOrCancelled == postOnly order
                      # 'iceberg': 0,  # amount to display for the iceberg order, null or 0 for normal orders, set to -1 to hide the order completely
                      # 'auto_borrow': False,  # used in margin or cross margin trading to allow automatic loan of insufficient amount if balance is not enough
                      # 'auto_repay': False,  # automatic repayment for automatic borrow loan generated by cross margin order, diabled by default
                  }
                  if timeInForce is not None:
                      request['time_in_force'] = timeInForce
              clientOrderId = self.safe_string_2(params, 'text', 'clientOrderId')
              if clientOrderId is not None:
                  # user-defined, must follow the rules if not empty
                  #     prefixed with t-
                  #     no longer than 28 bytes without t- prefix
                  #     can only include 0-9, A-Z, a-z, underscores(_), hyphens(-) or dots(.)
                  if len(clientOrderId) > 28:
                      raise BadRequest(self.id + ' createOrder() clientOrderId or text param must be up to 28 characters')
                  params = self.omit(params, ['text', 'clientOrderId'])
                  if clientOrderId[0] != 't':
                      clientOrderId = 't-' + clientOrderId
                  request['text'] = clientOrderId
          else:
              if contract:
                  # contract conditional order
                  rule = 1 if (side == 'buy') else 2
                  request = {
                      'initial': {
                          'contract': market['id'],
                          'size': amount,  # positive = buy, negative = sell, set to 0 to close the position
                          'price': self.price_to_precision(symbol, price),  # set to 0 to use market price
                          # 'close': False,  # set to True if trying to close the position
                          # 'tif': 'gtc',  # gtc, ioc, if using market price, only ioc is supported
                          # 'text': clientOrderId,  # web, api, app
                          # 'reduce_only': False,
                      },
                      'trigger': {
                          # 'strategy_type': 0,  # 0 = by price, 1 = by price gap, only 0 is supported currently
                          # 'price_type': 0,  # 0 latest deal price, 1 mark price, 2 index price
                          'price': self.price_to_precision(symbol, stopPrice),  # price or gap
                          'rule': rule,  # 1 means price_type >= price, 2 means price_type <= price
                          # 'expiration': expiration, how many seconds to wait for the condition to be triggered before cancelling the order
                      },
                      'settle': market['settleId'],
                  }
                  expiration = self.safe_integer(params, 'expiration')
                  if expiration is not None:
                      request['trigger']['expiration'] = expiration
                      params = self.omit(params, 'expiration')
                  if reduceOnly is not None:
                      request['initial']['reduce_only'] = reduceOnly
                  if timeInForce is not None:
                      request['initial']['tif'] = timeInForce
              else:
                  # spot conditional order
                  options = self.safe_value(self.options, 'createOrder', {})
                  marginMode = None
                  marginMode, params = self.get_margin_mode(True, params)
                  defaultExpiration = self.safe_integer(options, 'expiration')
                  expiration = self.safe_integer(params, 'expiration', defaultExpiration)
                  rule = '>=' if (side == 'buy') else '<='
                  triggerPrice = self.safe_value(trigger, 'price', stopPrice)
                  request = {
                      'trigger': {
                          'price': self.price_to_precision(symbol, triggerPrice),
                          'rule': rule,  # >= triggered when market price larger than or equal to price field, <= triggered when market price less than or equal to price field
                          'expiration': expiration,  # required, how long(in seconds) to wait for the condition to be triggered before cancelling the order
                      },
                      'put': {
                          'type': type,
                          'side': side,
                          'price': self.price_to_precision(symbol, price),
                          'amount': self.amount_to_precision(symbol, amount),
                          'account': marginMode,
                          'time_in_force': timeInForce,  # gtc, ioc for taker only
                      },
                      'market': market['id'],
                  }
              methodTail = 'PriceOrders'
          method = self.get_supported_mapping(market['type'], {
              'spot': 'privateSpotPost' + methodTail,
              'margin': 'privateSpotPost' + methodTail,
              'swap': 'privateFuturesPostSettle' + methodTail,
              'future': 'privateDeliveryPostSettle' + methodTail,
          })
          response = getattr(self, method)(self.deep_extend(request, params))
          #
          # spot
          #
          #     {
          #         "id": "95282841887",
          #         "text": "apiv4",
          #         "create_time": "1637383156",
          #         "update_time": "1637383156",
          #         "create_time_ms": 1637383156017,
          #         "update_time_ms": 1637383156017,
          #         "status": "open",
          #         "currency_pair": "ETH_USDT",
          #         "type": "limit",
          #         "account": "spot",
          #         "side": "buy",
          #         "amount": "0.01",
          #         "price": "3500",
          #         "time_in_force": "gtc",
          #         "iceberg": "0",
          #         "left": "0.01",
          #         "fill_price": "0",
          #         "filled_total": "0",
          #         "fee": "0",
          #         "fee_currency": "ETH",
          #         "point_fee": "0",
          #         "gt_fee": "0",
          #         "gt_discount": False,
          #         "rebated_fee": "0",
          #         "rebated_fee_currency": "USDT"
          #     }
          #
          # spot conditional
          #
          #     {"id": 5891843}
          #
          # future and perpetual swaps
          #
          #     {
          #         "id": 95938572327,
          #         "contract": "ETH_USDT",
          #         "mkfr": "0",
          #         "tkfr": "0.0005",
          #         "tif": "gtc",
          #         "is_reduce_only": False,
          #         "create_time": 1637384600.08,
          #         "price": "3000",
          #         "size": 1,
          #         "refr": "0",
          #         "left": 1,
          #         "text": "api",
          #         "fill_price": "0",
          #         "user": 2436035,
          #         "status": "open",
          #         "is_liq": False,
          #         "refu": 0,
          #         "is_close": False,
          #         "iceberg": 0
          #     }
          #
          # futures and perpetual swaps conditionals
          #
          #     {"id": 7615567}
          #
          return self.parse_order(response, market)
  
      def parse_order_status(self, status):
          statuses = {
              '_new': 'open',
              'filled': 'closed',
              'cancelled': 'canceled',
              'liquidated': 'closed',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_order(self, order, market=None):
          #
          # SPOT
          # createOrder/cancelOrder/fetchOrder
          #
          #    {
          #        "id": "62364648575",
          #        "text": "apiv4",
          #        "create_time": "1626354834",
          #        "update_time": "1626354834",
          #        "create_time_ms": "1626354833544",
          #        "update_time_ms": "1626354833544",
          #        "status": "open",
          #        "currency_pair": "BTC_USDT",
          #        "type": "limit",
          #        "account": "spot",
          #        "side": "buy",
          #        "amount": "0.0001",
          #        "price": "30000",
          #        "time_in_force": "gtc",
          #        "iceberg": "0",
          #        "left": "0.0001",
          #        "fill_price": "0",
          #        "filled_total": "0",
          #        "fee": "0",
          #        "fee_currency": "BTC",
          #        "point_fee": "0",
          #        "gt_fee": "0",
          #        "gt_discount": True,
          #        "rebated_fee": "0",
          #        "rebated_fee_currency": "USDT"
          #     }
          #
          # SPOT TRIGGER ORDERS
          # createOrder
          #
          #    {
          #        "id": 12604556
          #    }
          #
          # fetchOrder/cancelOrder
          #
          #    {
          #        "market": "ADA_USDT",
          #        "user": 6392049,
          #        "trigger": {
          #            "price": "1.08",  # stopPrice
          #            "rule": "\u003e=",
          #            "expiration": 86400
          #        },
          #        "put": {
          #            "type": "limit",
          #            "side": "buy",
          #            "price": "1.08",  # order price
          #            "amount": "1.00000000000000000000",
          #            "account": "normal",
          #            "time_in_force": "gtc"
          #        },
          #        "id": 71639298,
          #        "ctime": 1643945985,
          #        "status": "open"
          #    }
          #
          # FUTURE AND SWAP
          # createOrder/cancelOrder/fetchOrder
          #
          #    {
          #        "id": 123028481731,
          #        "contract": "ADA_USDT",
          #        "mkfr": "-0.00005",
          #        "tkfr": "0.00048",
          #        "tif": "ioc",
          #        "is_reduce_only": False,
          #        "create_time": 1643950262.68,
          #        "finish_time": 1643950262.68,
          #        "price": "0",
          #        "size": 1,
          #        "refr": "0",
          #        "left":0,
          #        "text": "api",
          #        "fill_price": "1.05273",
          #        "user":6329238,
          #        "finish_as": "filled",
          #        "status": "finished",
          #        "is_liq": False,
          #        "refu":0,
          #        "is_close": False,
          #        "iceberg": 0
          #    }
          #
          # TRIGGER ORDERS(FUTURE AND SWAP)
          # createOrder
          #
          #    {
          #        "id": 12604556
          #    }
          #
          # fetchOrder/cancelOrder
          #
          #    {
          #        "user": 6320300,
          #        "trigger": {
          #            "strategy_type": 0,
          #            "price_type": 0,
          #            "price": "1.03",  # stopPrice
          #            "rule": 2,
          #            "expiration": 0
          #        },
          #        "initial": {
          #            "contract": "ADA_USDT",
          #            "size": -1,
          #            "price": "1.02",
          #            "tif": "gtc",
          #            "text": "",
          #            "iceberg": 0,
          #            "is_close": False,
          #            "is_reduce_only": False,
          #            "auto_size": ""
          #        },
          #        "id": 126393906,
          #        "trade_id": 0,
          #        "status": "open",
          #        "reason": "",
          #        "create_time": 1643953482,
          #        "finish_time": 1643953482,
          #        "is_stop_order": False,
          #        "stop_trigger": {
          #            "rule": 0,
          #            "trigger_price": "",
          #            "order_price": ""
          #        },
          #        "me_order_id": 0,
          #        "order_type": ""
          #    }
          #
          put = self.safe_value_2(order, 'put', 'initial')
          trigger = self.safe_value(order, 'trigger')
          contract = self.safe_string(put, 'contract')
          type = self.safe_string(put, 'type')
          timeInForce = self.safe_string_upper_2(put, 'time_in_force', 'tif')
          amount = self.safe_string_2(put, 'amount', 'size')
          side = self.safe_string(put, 'side')
          price = self.safe_string(put, 'price')
          contract = self.safe_string(order, 'contract', contract)
          type = self.safe_string(order, 'type', type)
          timeInForce = self.safe_string_upper_2(order, 'time_in_force', 'tif', timeInForce)
          if timeInForce == 'POC':
              timeInForce = 'PO'
          postOnly = (timeInForce == 'PO')
          amount = self.safe_string_2(order, 'amount', 'size', amount)
          side = self.safe_string(order, 'side', side)
          price = self.safe_string(order, 'price', price)
          remaining = self.safe_string(order, 'left')
          filled = Precise.string_sub(amount, remaining)
          cost = self.safe_string(order, 'filled_total')
          rawStatus = None
          average = None
          if put:
              remaining = amount
              filled = '0'
              cost = '0'
          if contract:
              isMarketOrder = Precise.string_equals(price, '0') and (timeInForce == 'IOC')
              type = 'market' if isMarketOrder else 'limit'
              side = 'buy' if Precise.string_gt(amount, '0') else 'sell'
              rawStatus = self.safe_string(order, 'finish_as', 'open')
              average = self.safe_number(order, 'fill_price')
          else:
              rawStatus = self.safe_string(order, 'status')
          timestamp = self.safe_integer(order, 'create_time_ms')
          if timestamp is None:
              timestamp = self.safe_timestamp_2(order, 'create_time', 'ctime')
          lastTradeTimestamp = self.safe_integer(order, 'update_time_ms')
          if lastTradeTimestamp is None:
              lastTradeTimestamp = self.safe_timestamp_2(order, 'update_time', 'finish_time')
          exchangeSymbol = self.safe_string_2(order, 'currency_pair', 'market', contract)
          # Everything below self(above return) is related to fees
          fees = []
          gtFee = self.safe_string(order, 'gt_fee')
          if gtFee:
              fees.append({
                  'currency': 'GT',
                  'cost': gtFee,
              })
          fee = self.safe_string(order, 'fee')
          if fee:
              fees.append({
                  'currency': self.safe_currency_code(self.safe_string(order, 'fee_currency')),
                  'cost': fee,
              })
          rebate = self.safe_string(order, 'rebated_fee')
          if rebate:
              fees.append({
                  'currency': self.safe_currency_code(self.safe_string(order, 'rebated_fee_currency')),
                  'cost': Precise.string_neg(rebate),
              })
          numFeeCurrencies = len(fees)
          multipleFeeCurrencies = numFeeCurrencies > 1
          status = self.parse_order_status(rawStatus)
          return self.safe_order({
              'id': self.safe_string(order, 'id'),
              'clientOrderId': self.safe_string(order, 'text'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': lastTradeTimestamp,
              'status': status,
              'symbol': self.safe_symbol(exchangeSymbol),
              'type': type,
              'timeInForce': timeInForce,
              'postOnly': postOnly,
              'reduceOnly': self.safe_value(order, 'is_reduce_only'),
              'side': side,
              'price': self.parse_number(price),
              'stopPrice': self.safe_number(trigger, 'price'),
              'average': average,
              'amount': self.parse_number(Precise.string_abs(amount)),
              'cost': Precise.string_abs(cost),
              'filled': self.parse_number(Precise.string_abs(filled)),
              'remaining': self.parse_number(Precise.string_abs(remaining)),
              'fee': None if multipleFeeCurrencies else self.safe_value(fees, 0),
              'fees': fees if multipleFeeCurrencies else [],
              'trades': None,
              'info': order,
          }, market)
  
      def fetch_order(self, id, symbol=None, params={}):
          """
          Retrieves information on an order
          :param str id: Order id
          :param str symbol: Unified market symbol, *required for spot and margin*
          :param dict params: Parameters specified by the exchange api
          :param bool params['stop']: True if the order being fetched is a trigger order
          :param str params['marginMode']: 'cross' or 'isolated' - marginMode for margin trading if not provided self.options['defaultMarginMode'] is used
          :param str params['type']: 'spot', 'swap', or 'future', if not provided self.options['defaultMarginMode'] is used
          :param str params['settle']: 'btc' or 'usdt' - settle currency for perpetual swap and future - market settle currency is used if symbol is not None, default="usdt" for swap and "btc" for future
          :returns: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
          """
          self.load_markets()
          stop = self.safe_value_2(params, 'is_stop_order', 'stop', False)
          params = self.omit(params, ['is_stop_order', 'stop'])
          clientOrderId = self.safe_string_2(params, 'text', 'clientOrderId')
          orderId = id
          if clientOrderId is not None:
              params = self.omit(params, ['text', 'clientOrderId'])
              if clientOrderId[0] != 't':
                  clientOrderId = 't-' + clientOrderId
              orderId = clientOrderId
          market = None if (symbol is None) else self.market(symbol)
          type, query = self.handle_market_type_and_params('fetchOrder', market, params)
          contract = (type == 'swap') or (type == 'future')
          request, requestParams = self.prepare_request(market, type, query) if contract else self.spot_order_prepare_request(market, stop, query)
          request['order_id'] = orderId
          methodMiddle = 'PriceOrders' if stop else 'Orders'
          method = self.get_supported_mapping(type, {
              'spot': 'privateSpotGet' + methodMiddle + 'OrderId',
              'margin': 'privateSpotGet' + methodMiddle + 'OrderId',
              'swap': 'privateFuturesGetSettle' + methodMiddle + 'OrderId',
              'future': 'privateDeliveryGetSettle' + methodMiddle + 'OrderId',
          })
          response = getattr(self, method)(self.extend(request, requestParams))
          return self.parse_order(response, market)
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          """
          fetches all open orders
          :param str symbol: Unified market symbol
          :param int since: earliest time in ms for orders in the response
          :param int limit: max number of order structures to return
          :param dict params: exchange specific params
          :param bool params['stop']: True for fetching stop orders
          :param str params['type']: spot, margin, swap or future, if not provided self.options['defaultType'] is used
          :param str params['marginMode']: 'cross' or 'isolated' - marginMode for type='margin', if not provided self.options['defaultMarginMode'] is used
          :returns: An array of order structures
          """
          return self.fetch_orders_by_status('open', symbol, since, limit, params)
  
      def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          """
          fetches all closed orders
          :param str symbol: Unified market symbol of the market to fetch orders for
          :param int since: earliest time in ms for orders in the response
          :param int limit: max number of order structures to return
          :param dict params: exchange specific params
          :param bool params['stop']: True for fetching stop orders
          :param str params['type']: spot, swap or future, if not provided self.options['defaultType'] is used
          :param str params['marginMode']: 'cross' or 'isolated' - marginMode for margin trading if not provided self.options['defaultMarginMode'] is used
          :returns: An array of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
          """
          return self.fetch_orders_by_status('finished', symbol, since, limit, params)
  
      def fetch_orders_by_status(self, status, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          market = None if (symbol is None) else self.market(symbol)
          stop = self.safe_value(params, 'stop')
          params = self.omit(params, 'stop')
          type, query = self.handle_market_type_and_params('fetchOrdersByStatus', market, params)
          spot = (type == 'spot') or (type == 'margin')
          request, requestParams = self.multi_order_spot_prepare_request(market, stop, query) if spot else self.prepare_request(market, type, query)
          if status == 'closed':
              status = 'finished'
          request['status'] = status
          if limit is not None:
              request['limit'] = limit
          if since is not None and spot:
              request['from'] = int(since / 1000)
          methodTail = 'PriceOrders' if stop else 'Orders'
          openSpotOrders = spot and (status == 'open') and not stop
          if openSpotOrders:
              methodTail = 'OpenOrders'
          method = self.get_supported_mapping(type, {
              'spot': 'privateSpotGet' + methodTail,
              'margin': 'privateSpotGet' + methodTail,
              'swap': 'privateFuturesGetSettle' + methodTail,
              'future': 'privateDeliveryGetSettle' + methodTail,
          })
          response = getattr(self, method)(self.extend(request, requestParams))
          #
          # SPOT Open Orders
          #
          #    [
          #        {
          #            "currency_pair": "ADA_USDT",
          #            "total": 2,
          #            "orders": [
          #                {
          #                    "id": "155498539874",
          #                    "text": "apiv4",
          #                    "create_time": "1652406843",
          #                    "update_time": "1652406843",
          #                    "create_time_ms": 1652406843295,
          #                    "update_time_ms": 1652406843295,
          #                    "status": "open",
          #                    "currency_pair": "ADA_USDT",
          #                    "type": "limit",
          #                    "account": "spot",
          #                    "side": "buy",
          #                    "amount": "3",
          #                    "price": "0.35",
          #                    "time_in_force": "gtc",
          #                    "iceberg": "0",
          #                    "left": "3",
          #                    "fill_price": "0",
          #                    "filled_total": "0",
          #                    "fee": "0",
          #                    "fee_currency": "ADA",
          #                    "point_fee": "0",
          #                    "gt_fee": "0",
          #                    "gt_discount": False,
          #                    "rebated_fee": "0",
          #                    "rebated_fee_currency": "USDT"
          #                },
          #                ...
          #            ]
          #        },
          #        ...
          #    ]
          #
          # SPOT
          #
          #    [
          #        {
          #           "id": "8834234273",
          #           "text": "3",
          #           "create_time": "1635406193",
          #           "update_time": "1635406193",
          #           "create_time_ms": 1635406193361,
          #           "update_time_ms": 1635406193361,
          #           "status": "closed",
          #           "currency_pair": "BTC_USDT",
          #           "type": "limit",
          #           "account": "spot",  # margin for margin orders
          #           "side": "sell",
          #           "amount": "0.0002",
          #           "price": "58904.01",
          #           "time_in_force": "gtc",
          #           "iceberg": "0",
          #           "left": "0.0000",
          #           "fill_price": "11.790516",
          #           "filled_total": "11.790516",
          #           "fee": "0.023581032",
          #           "fee_currency": "USDT",
          #           "point_fee": "0",
          #           "gt_fee": "0",
          #           "gt_discount": False,
          #           "rebated_fee_currency": "BTC"
          #        }
          #    ]
          #
          # Spot Stop
          #
          #    [
          #        {
          #            "market": "ADA_USDT",
          #            "user": 10406147,
          #            "trigger": {
          #                "price": "0.65",
          #                "rule": "\u003c=",
          #                "expiration": 86400
          #            },
          #            "put": {
          #                "type": "limit",
          #                "side": "sell",
          #                "price": "0.65",
          #                "amount": "2.00000000000000000000",
          #                "account": "normal",  # margin for margin orders
          #                "time_in_force": "gtc"
          #            },
          #            "id": 8449909,
          #            "ctime": 1652188982,
          #            "status": "open"
          #        }
          #    ]
          #
          # Perpetual Swap
          #
          #    [
          #        {
          #           "status": "finished",
          #           "size": -1,
          #           "left": 0,
          #           "id": 82750739203,
          #           "is_liq": False,
          #           "is_close": False,
          #           "contract": "BTC_USDT",
          #           "text": "web",
          #           "fill_price": "60721.3",
          #           "finish_as": "filled",
          #           "iceberg": 0,
          #           "tif": "ioc",
          #           "is_reduce_only": True,
          #           "create_time": 1635403475.412,
          #           "finish_time": 1635403475.4127,
          #           "price": "0"
          #        }
          #    ]
          #
          result = response
          if openSpotOrders:
              result = []
              for i in range(0, len(response)):
                  orders = self.safe_value(response[i], 'orders')
                  result = self.array_concat(result, orders)
          orders = self.parse_orders(result, market, since, limit)
          return self.filter_by_symbol_since_limit(orders, symbol, since, limit)
  
      def cancel_order(self, id, symbol=None, params={}):
          """
          Cancels an open order
          :param str id: Order id
          :param str symbol: Unified market symbol
          :param dict params: Parameters specified by the exchange api
          :param bool params['stop']: True if the order to be cancelled is a trigger order
          :returns: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
          """
          self.load_markets()
          market = None if (symbol is None) else self.market(symbol)
          stop = self.safe_value_2(params, 'is_stop_order', 'stop', False)
          params = self.omit(params, ['is_stop_order', 'stop'])
          type, query = self.handle_market_type_and_params('cancelOrder', market, params)
          request, requestParams = self.spot_order_prepare_request(market, stop, query) if (type == 'spot' or type == 'margin') else self.prepare_request(market, type, query)
          request['order_id'] = id
          pathMiddle = 'Price' if stop else ''
          method = self.get_supported_mapping(type, {
              'spot': 'privateSpotDelete' + pathMiddle + 'OrdersOrderId',
              'margin': 'privateSpotDelete' + pathMiddle + 'OrdersOrderId',
              'swap': 'privateFuturesDeleteSettle' + pathMiddle + 'OrdersOrderId',
              'future': 'privateDeliveryDeleteSettle' + pathMiddle + 'OrdersOrderId',
          })
          response = getattr(self, method)(self.extend(request, requestParams))
          #
          # spot
          #
          #     {
          #         "id": "95282841887",
          #         "text": "apiv4",
          #         "create_time": "1637383156",
          #         "update_time": "1637383235",
          #         "create_time_ms": 1637383156017,
          #         "update_time_ms": 1637383235085,
          #         "status": "cancelled",
          #         "currency_pair": "ETH_USDT",
          #         "type": "limit",
          #         "account": "spot",
          #         "side": "buy",
          #         "amount": "0.01",
          #         "price": "3500",
          #         "time_in_force": "gtc",
          #         "iceberg": "0",
          #         "left": "0.01",
          #         "fill_price": "0",
          #         "filled_total": "0",
          #         "fee": "0",
          #         "fee_currency": "ETH",
          #         "point_fee": "0",
          #         "gt_fee": "0",
          #         "gt_discount": False,
          #         "rebated_fee": "0",
          #         "rebated_fee_currency": "USDT"
          #     }
          #
          # spot conditional
          #
          #     {
          #         "market": "ETH_USDT",
          #         "user": 2436035,
          #         "trigger": {
          #             "price": "3500",
          #             "rule": "\u003c=",
          #             "expiration": 86400
          #         },
          #         "put": {
          #             "type": "limit",
          #             "side": "buy",
          #             "price": "3500",
          #             "amount": "0.01000000000000000000",
          #             "account": "normal",
          #             "time_in_force": "gtc"
          #         },
          #         "id": 5891843,
          #         "ctime": 1637382379,
          #         "ftime": 1637382673,
          #         "status": "canceled"
          #     }
          #
          # perpetual swaps
          #
          #     {
          #         id: "82241928192",
          #         contract: "BTC_USDT",
          #         mkfr: "0",
          #         tkfr: "0.0005",
          #         tif: "gtc",
          #         is_reduce_only: False,
          #         create_time: "1635196145.06",
          #         finish_time: "1635196233.396",
          #         price: "61000",
          #         size: "4",
          #         refr: "0",
          #         left: "4",
          #         text: "web",
          #         fill_price: "0",
          #         user: "6693577",
          #         finish_as: "cancelled",
          #         status: "finished",
          #         is_liq: False,
          #         refu: "0",
          #         is_close: False,
          #         iceberg: "0",
          #     }
          #
          return self.parse_order(response, market)
  
      def cancel_all_orders(self, symbol=None, params={}):
          self.load_markets()
          market = None if (symbol is None) else self.market(symbol)
          stop = self.safe_value(params, 'stop')
          params = self.omit(params, 'stop')
          type, query = self.handle_market_type_and_params('cancelAllOrders', market, params)
          request, requestParams = self.multi_order_spot_prepare_request(market, stop, query) if (type == 'spot') else self.prepare_request(market, type, query)
          methodTail = 'PriceOrders' if stop else 'Orders'
          method = self.get_supported_mapping(type, {
              'spot': 'privateSpotDelete' + methodTail,
              'margin': 'privateSpotDelete' + methodTail,
              'swap': 'privateFuturesDeleteSettle' + methodTail,
              'future': 'privateDeliveryDeleteSettle' + methodTail,
          })
          response = getattr(self, method)(self.extend(request, requestParams))
          #
          #    [
          #        {
          #            "id": 139797004085,
          #            "contract": "ADA_USDT",
          #            "mkfr": "0",
          #            "tkfr": "0.0005",
          #            "tif": "gtc",
          #            "is_reduce_only": False,
          #            "create_time": 1647911169.343,
          #            "finish_time": 1647911226.849,
          #            "price": "0.8",
          #            "size": 1,
          #            "refr": "0.3",
          #            "left": 1,
          #            "text": "api",
          #            "fill_price": "0",
          #            "user": 6693577,
          #            "finish_as": "cancelled",
          #            "status": "finished",
          #            "is_liq": False,
          #            "refu": 2436035,
          #            "is_close": False,
          #            "iceberg": 0
          #        }
          #        ...
          #    ]
          #
          return self.parse_orders(response, market)
  
      def transfer(self, code, amount, fromAccount, toAccount, params={}):
          """
          makes internal transfers of funds between accounts on the same exchange
          :param str code: unified currency code for currency being transferred
          :param float amount: the amount of currency to transfer
          :param str fromAccount: the account to transfer currency from
          :param str toAccount: the account to transfer currency to
          :param dict params: Exchange specific parameters
          :param dict params['symbol']: Unified market symbol *required for type == margin*
          :returns: A `transfer structure <https://docs.ccxt.com/en/latest/manual.html#transfer-structure>`
          """
          self.load_markets()
          currency = self.currency(code)
          fromId = self.parse_account(fromAccount)
          toId = self.parse_account(toAccount)
          truncated = self.currency_to_precision(code, amount)
          request = {
              'currency': currency['id'],
              'amount': truncated,
          }
          if not (fromId in self.options['accountsByType']):
              request['from'] = 'margin'
              request['currency_pair'] = fromId
          else:
              request['from'] = fromId
          if not (toId in self.options['accountsByType']):
              request['to'] = 'margin'
              request['currency_pair'] = toId
          else:
              request['to'] = toId
          if fromId == 'margin' or toId == 'margin':
              symbol = self.safe_string_2(params, 'symbol', 'currency_pair')
              if symbol is None:
                  raise ArgumentsRequired(self.id + ' transfer requires params["symbol"] for isolated margin transfers')
              market = self.market(symbol)
              request['currency_pair'] = market['id']
              params = self.omit(params, 'symbol')
          if (toId == 'futures') or (toId == 'delivery') or (fromId == 'futures') or (fromId == 'delivery'):
              request['settle'] = currency['lowerCaseId']
          response = self.privateWalletPostTransfers(self.extend(request, params))
          #
          # according to the docs(however actual response seems to be an empty string '')
          #
          #    {
          #        "currency": "BTC",
          #        "from": "spot",
          #        "to": "margin",
          #        "amount": "1",
          #        "currency_pair": "BTC_USDT"
          #    }
          #
          transfer = self.parse_transfer(response, currency)
          return self.extend(transfer, {
              'fromAccount': fromAccount,
              'toAccount': toAccount,
              'amount': self.parse_number(truncated),
          })
  
      def parse_account(self, account):
          accountsByType = self.options['accountsByType']
          if account in accountsByType:
              return accountsByType[account]
          elif account in self.markets:
              market = self.market(account)
              return market['id']
          else:
              keys = list(accountsByType.keys())
              raise ExchangeError(self.id + ' accounts must be one of ' + ', '.join(keys) + ' or an isolated margin symbol')
  
      def parse_transfer(self, transfer, currency=None):
          timestamp = self.milliseconds()
          return {
              'id': None,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'currency': self.safe_currency_code(None, currency),
              'amount': None,
              'fromAccount': None,
              'toAccount': None,
              'status': None,
              'info': transfer,
          }
  
      def set_leverage(self, leverage, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
          # WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
          # AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
          if (leverage < 0) or (leverage > 100):
              raise BadRequest(self.id + ' setLeverage() leverage should be between 1 and 100')
          self.load_markets()
          market = self.market(symbol)
          method = self.get_supported_mapping(market['type'], {
              'swap': 'privateFuturesPostSettlePositionsContractLeverage',
              'future': 'privateDeliveryPostSettlePositionsContractLeverage',
          })
          request, query = self.prepare_request(market, None, params)
          defaultMarginMode = self.safe_string_2(self.options, 'marginMode', 'defaultMarginMode')
          crossLeverageLimit = self.safe_string(query, 'cross_leverage_limit')
          marginMode = self.safe_string(query, 'marginMode', defaultMarginMode)
          if crossLeverageLimit is not None:
              marginMode = 'cross'
              leverage = crossLeverageLimit
          if marginMode == 'cross' or marginMode == 'cross_margin':
              request['query'] = {
                  'cross_leverage_limit': str(leverage),
                  'leverage': '0',
              }
          else:
              request['query'] = {
                  'leverage': str(leverage),
              }
          response = getattr(self, method)(self.extend(request, query))
          #
          #     {
          #         "value": "0",
          #         "leverage": "5",
          #         "mode": "single",
          #         "realised_point": "0",
          #         "contract": "BTC_USDT",
          #         "entry_price": "0",
          #         "mark_price": "62035.86",
          #         "history_point": "0",
          #         "realised_pnl": "0",
          #         "close_order": null,
          #         "size": 0,
          #         "cross_leverage_limit": "0",
          #         "pending_orders": 0,
          #         "adl_ranking": 6,
          #         "maintenance_rate": "0.005",
          #         "unrealised_pnl": "0",
          #         "user": 2436035,
          #         "leverage_max": "100",
          #         "history_pnl": "0",
          #         "risk_limit": "1000000",
          #         "margin": "0",
          #         "last_close_pnl": "0",
          #         "liq_price": "0"
          #     }
          #
          return response
  
      def parse_position(self, position, market=None):
          #
          #     {
          #         value: "12.475572",
          #         leverage: "0",
          #         mode: "single",
          #         realised_point: "0",
          #         contract: "BTC_USDT",
          #         entry_price: "62422.6",
          #         mark_price: "62377.86",
          #         history_point: "0",
          #         realised_pnl: "-0.00624226",
          #         close_order:  null,
          #         size: "2",
          #         cross_leverage_limit: "25",
          #         pending_orders: "0",
          #         adl_ranking: "5",
          #         maintenance_rate: "0.005",
          #         unrealised_pnl: "-0.008948",
          #         user: "663337",
          #         leverage_max: "100",
          #         history_pnl: "14.98868396636",
          #         risk_limit: "1000000",
          #         margin: "0.740721495056",
          #         last_close_pnl: "-0.041996015",
          #         liq_price: "59058.58"
          #     }
          #
          contract = self.safe_string(position, 'contract')
          market = self.safe_market(contract, market)
          size = self.safe_string(position, 'size')
          side = None
          if Precise.string_gt(size, '0'):
              side = 'long'
          elif Precise.string_lt(size, '0'):
              side = 'short'
          maintenanceRate = self.safe_string(position, 'maintenance_rate')
          notional = self.safe_string(position, 'value')
          leverage = self.safe_string(position, 'leverage')
          marginMode = None
          if leverage == '0':
              marginMode = 'cross'
          else:
              marginMode = 'isolated'
          unrealisedPnl = self.safe_string(position, 'unrealised_pnl')
          # Initial Position Margin = ( Position Value / Leverage ) + Close Position Fee
          # *The default leverage under the full position is the highest leverage in the market.
          # *Trading fee is charged as Taker Fee Rate(0.075%).
          takerFee = '0.00075'
          feePaid = Precise.string_mul(takerFee, notional)
          initialMarginString = Precise.string_add(Precise.string_div(notional, leverage), feePaid)
          percentage = Precise.string_mul(Precise.string_div(unrealisedPnl, initialMarginString), '100')
          return {
              'info': position,
              'symbol': self.safe_string(market, 'symbol'),
              'timestamp': None,
              'datetime': None,
              'initialMargin': self.parse_number(initialMarginString),
              'initialMarginPercentage': self.parse_number(Precise.string_div(initialMarginString, notional)),
              'maintenanceMargin': self.parse_number(Precise.string_mul(maintenanceRate, notional)),
              'maintenanceMarginPercentage': self.parse_number(maintenanceRate),
              'entryPrice': self.safe_number(position, 'entry_price'),
              'notional': self.parse_number(notional),
              'leverage': self.safe_number(position, 'leverage'),
              'unrealizedPnl': self.parse_number(unrealisedPnl),
              'contracts': self.parse_number(Precise.string_abs(size)),
              'contractSize': self.safe_value(market, 'contractSize'),
              # 'realisedPnl': position['realised_pnl'],
              'marginRatio': None,
              'liquidationPrice': self.safe_number(position, 'liq_price'),
              'markPrice': self.safe_number(position, 'mark_price'),
              'collateral': self.safe_number(position, 'margin'),
              'marginMode': marginMode,
              'marginType': marginMode,  # deprecated
              'side': side,
              'percentage': self.parse_number(percentage),
          }
  
      def parse_positions(self, positions):
          result = []
          for i in range(0, len(positions)):
              result.append(self.parse_position(positions[i]))
          return result
  
      def fetch_positions(self, symbols=None, params={}):
          """
          Fetch trades positions
           * @param {[str]} symbols Not used by Gateio, but parsed internally by CCXT
          :param dict params: exchange specific parameters
          :param str params['settle']: 'btc' or 'usdt' - settle currency for perpetual swap and future - default="usdt" for swap and "btc" for future
          :param str params['type']: swap or future, if not provided self.options['defaultType'] is used
          :returns: An array of `position structures <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
          """
          self.load_markets()
          type, query = self.handle_market_type_and_params('fetchPositions', None, params)
          request, requestParams = self.prepare_request(None, type, query)
          method = self.get_supported_mapping(type, {
              'swap': 'privateFuturesGetSettlePositions',
              'future': 'privateDeliveryGetSettlePositions',
          })
          response = getattr(self, method)(self.extend(request, requestParams))
          #
          #     [
          #         {
          #             value: "12.475572",
          #             leverage: "0",
          #             mode: "single",
          #             realised_point: "0",
          #             contract: "BTC_USDT",
          #             entry_price: "62422.6",
          #             mark_price: "62377.86",
          #             history_point: "0",
          #             realised_pnl: "-0.00624226",
          #             close_order:  null,
          #             size: "2",
          #             cross_leverage_limit: "25",
          #             pending_orders: "0",
          #             adl_ranking: "5",
          #             maintenance_rate: "0.005",
          #             unrealised_pnl: "-0.008948",
          #             user: "6693577",
          #             leverage_max: "100",
          #             history_pnl: "14.98868396636",
          #             risk_limit: "1000000",
          #             margin: "0.740721495056",
          #             last_close_pnl: "-0.041996015",
          #             liq_price: "59058.58"
          #         }
          #     ]
          #
          result = self.parse_positions(response)
          return self.filter_by_array(result, 'symbol', symbols, False)
  
      def fetch_leverage_tiers(self, symbols=None, params={}):
          self.load_markets()
          type, query = self.handle_market_type_and_params('fetchLeverageTiers', None, params)
          request, requestParams = self.prepare_request(None, type, query)
          if type != 'future' and type != 'swap':
              raise BadRequest(self.id + ' fetchLeverageTiers only supports swap and future')
          method = self.get_supported_mapping(type, {
              'swap': 'publicFuturesGetSettleContracts',
              'future': 'publicDeliveryGetSettleContracts',
          })
          response = getattr(self, method)(self.extend(request, requestParams))
          #
          # Perpetual swap
          #
          #    [
          #        {
          #            "name": "BTC_USDT",
          #            "type": "direct",
          #            "quanto_multiplier": "0.0001",
          #            "ref_discount_rate": "0",
          #            "order_price_deviate": "0.5",
          #            "maintenance_rate": "0.005",
          #            "mark_type": "index",
          #            "last_price": "38026",
          #            "mark_price": "37985.6",
          #            "index_price": "37954.92",
          #            "funding_rate_indicative": "0.000219",
          #            "mark_price_round": "0.01",
          #            "funding_offset": 0,
          #            "in_delisting": False,
          #            "risk_limit_base": "1000000",
          #            "interest_rate": "0.0003",
          #            "order_price_round": "0.1",
          #            "order_size_min": 1,
          #            "ref_rebate_rate": "0.2",
          #            "funding_interval": 28800,
          #            "risk_limit_step": "1000000",
          #            "leverage_min": "1",
          #            "leverage_max": "100",
          #            "risk_limit_max": "8000000",
          #            "maker_fee_rate": "-0.00025",
          #            "taker_fee_rate": "0.00075",
          #            "funding_rate": "0.002053",
          #            "order_size_max": 1000000,
          #            "funding_next_apply": 1610035200,
          #            "short_users": 977,
          #            "config_change_time": 1609899548,
          #            "trade_size": 28530850594,
          #            "position_size": 5223816,
          #            "long_users": 455,
          #            "funding_impact_value": "60000",
          #            "orders_limit": 50,
          #            "trade_id": 10851092,
          #            "orderbook_id": 2129638396
          #        }
          #    ]
          #
          # Delivery Futures
          #
          #    [
          #        {
          #            "name": "BTC_USDT_20200814",
          #            "underlying": "BTC_USDT",
          #            "cycle": "WEEKLY",
          #            "type": "direct",
          #            "quanto_multiplier": "0.0001",
          #            "mark_type": "index",
          #            "last_price": "9017",
          #            "mark_price": "9019",
          #            "index_price": "9005.3",
          #            "basis_rate": "0.185095",
          #            "basis_value": "13.7",
          #            "basis_impact_value": "100000",
          #            "settle_price": "0",
          #            "settle_price_interval": 60,
          #            "settle_price_duration": 1800,
          #            "settle_fee_rate": "0.0015",
          #            "expire_time": 1593763200,
          #            "order_price_round": "0.1",
          #            "mark_price_round": "0.1",
          #            "leverage_min": "1",
          #            "leverage_max": "100",
          #            "maintenance_rate": "1000000",
          #            "risk_limit_base": "140.726652109199",
          #            "risk_limit_step": "1000000",
          #            "risk_limit_max": "8000000",
          #            "maker_fee_rate": "-0.00025",
          #            "taker_fee_rate": "0.00075",
          #            "ref_discount_rate": "0",
          #            "ref_rebate_rate": "0.2",
          #            "order_price_deviate": "0.5",
          #            "order_size_min": 1,
          #            "order_size_max": 1000000,
          #            "orders_limit": 50,
          #            "orderbook_id": 63,
          #            "trade_id": 26,
          #            "trade_size": 435,
          #            "position_size": 130,
          #            "config_change_time": 1593158867,
          #            "in_delisting": False
          #        }
          #    ]
          #
          return self.parse_leverage_tiers(response, symbols, 'name')
  
      def parse_market_leverage_tiers(self, info, market=None):
          """
           * @ignore
          https://www.gate.io/help/futures/perpetual/22162/instrctions-of-risk-limit
          :param dict info: Exchange market response for 1 market
          :param dict market: CCXT market
          """
          #
          # Perpetual swap
          #
          #    {
          #        "name": "BTC_USDT",
          #        "type": "direct",
          #        "quanto_multiplier": "0.0001",
          #        "ref_discount_rate": "0",
          #        "order_price_deviate": "0.5",
          #        "maintenance_rate": "0.005",
          #        "mark_type": "index",
          #        "last_price": "38026",
          #        "mark_price": "37985.6",
          #        "index_price": "37954.92",
          #        "funding_rate_indicative": "0.000219",
          #        "mark_price_round": "0.01",
          #        "funding_offset": 0,
          #        "in_delisting": False,
          #        "risk_limit_base": "1000000",
          #        "interest_rate": "0.0003",
          #        "order_price_round": "0.1",
          #        "order_size_min": 1,
          #        "ref_rebate_rate": "0.2",
          #        "funding_interval": 28800,
          #        "risk_limit_step": "1000000",
          #        "leverage_min": "1",
          #        "leverage_max": "100",
          #        "risk_limit_max": "8000000",
          #        "maker_fee_rate": "-0.00025",
          #        "taker_fee_rate": "0.00075",
          #        "funding_rate": "0.002053",
          #        "order_size_max": 1000000,
          #        "funding_next_apply": 1610035200,
          #        "short_users": 977,
          #        "config_change_time": 1609899548,
          #        "trade_size": 28530850594,
          #        "position_size": 5223816,
          #        "long_users": 455,
          #        "funding_impact_value": "60000",
          #        "orders_limit": 50,
          #        "trade_id": 10851092,
          #        "orderbook_id": 2129638396
          #    }
          #
          # Delivery Futures
          #
          #    {
          #        "name": "BTC_USDT_20200814",
          #        "underlying": "BTC_USDT",
          #        "cycle": "WEEKLY",
          #        "type": "direct",
          #        "quanto_multiplier": "0.0001",
          #        "mark_type": "index",
          #        "last_price": "9017",
          #        "mark_price": "9019",
          #        "index_price": "9005.3",
          #        "basis_rate": "0.185095",
          #        "basis_value": "13.7",
          #        "basis_impact_value": "100000",
          #        "settle_price": "0",
          #        "settle_price_interval": 60,
          #        "settle_price_duration": 1800,
          #        "settle_fee_rate": "0.0015",
          #        "expire_time": 1593763200,
          #        "order_price_round": "0.1",
          #        "mark_price_round": "0.1",
          #        "leverage_min": "1",
          #        "leverage_max": "100",
          #        "maintenance_rate": "1000000",
          #        "risk_limit_base": "140.726652109199",
          #        "risk_limit_step": "1000000",
          #        "risk_limit_max": "8000000",
          #        "maker_fee_rate": "-0.00025",
          #        "taker_fee_rate": "0.00075",
          #        "ref_discount_rate": "0",
          #        "ref_rebate_rate": "0.2",
          #        "order_price_deviate": "0.5",
          #        "order_size_min": 1,
          #        "order_size_max": 1000000,
          #        "orders_limit": 50,
          #        "orderbook_id": 63,
          #        "trade_id": 26,
          #        "trade_size": 435,
          #        "position_size": 130,
          #        "config_change_time": 1593158867,
          #        "in_delisting": False
          #    }
          #
          maintenanceMarginUnit = self.safe_string(info, 'maintenance_rate')  # '0.005',
          leverageMax = self.safe_string(info, 'leverage_max')  # '100',
          riskLimitStep = self.safe_string(info, 'risk_limit_step')  # '1000000',
          riskLimitMax = self.safe_string(info, 'risk_limit_max')  # '16000000',
          initialMarginUnit = Precise.string_div('1', leverageMax)
          maintenanceMarginRate = maintenanceMarginUnit
          initialMarginRatio = initialMarginUnit
          floor = '0'
          tiers = []
          while(Precise.string_lt(floor, riskLimitMax)):
              cap = Precise.string_add(floor, riskLimitStep)
              tiers.append({
                  'tier': self.parse_number(Precise.string_div(cap, riskLimitStep)),
                  'currency': self.safe_string(market, 'settle'),
                  'minNotional': self.parse_number(floor),
                  'maxNotional': self.parse_number(cap),
                  'maintenanceMarginRate': self.parse_number(maintenanceMarginRate),
                  'maxLeverage': self.parse_number(Precise.string_div('1', initialMarginRatio)),
                  'info': info,
              })
              maintenanceMarginRate = Precise.string_add(maintenanceMarginRate, maintenanceMarginUnit)
              initialMarginRatio = Precise.string_add(initialMarginRatio, initialMarginUnit)
              floor = cap
          return tiers
  
      def sign(self, path, api=[], method='GET', params={}, headers=None, body=None):
          authentication = api[0]  # public, private
          type = api[1]  # spot, margin, future, delivery
          query = self.omit(params, self.extract_params(path))
          path = self.implode_params(path, params)
          endPart = '' if (path == '') else ('/' + path)
          entirePath = '/' + type + endPart
          url = self.urls['api'][authentication][type]
          if url is None:
              raise NotSupported(self.id + ' does not have a testnet for the ' + type + ' market type.')
          url += entirePath
          if authentication == 'public':
              if query:
                  url += '?' + self.urlencode(query)
          else:
              queryString = ''
              if (method == 'GET') or (method == 'DELETE'):
                  if query:
                      queryString = self.urlencode(query)
                      url += '?' + queryString
              else:
                  urlQueryParams = self.safe_value(query, 'query', {})
                  if urlQueryParams:
                      queryString = self.urlencode(urlQueryParams)
                      url += '?' + queryString
                  query = self.omit(query, 'query')
                  body = self.json(query)
              bodyPayload = '' if (body is None) else body
              bodySignature = self.hash(self.encode(bodyPayload), 'sha512')
              timestamp = self.seconds()
              timestampString = str(timestamp)
              signaturePath = '/api/' + self.version + entirePath
              payloadArray = [method.upper(), signaturePath, queryString, bodySignature, timestampString]
              # eslint-disable-next-line quotes
              payload = "\n".join(payloadArray)
              signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha512)
              headers = {
                  'KEY': self.apiKey,
                  'Timestamp': timestampString,
                  'SIGN': signature,
                  'Content-Type': 'application/json',
              }
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if response is None:
              return
          #
          #    {"label": "ORDER_NOT_FOUND", "message": "Order not found"}
          #    {"label": "INVALID_PARAM_VALUE", "message": "invalid argument: status"}
          #    {"label": "INVALID_PARAM_VALUE", "message": "invalid argument: Trigger.rule"}
          #    {"label": "INVALID_PARAM_VALUE", "message": "invalid argument: trigger.expiration invalid range"}
          #    {"label": "INVALID_ARGUMENT", "detail": "invalid size"}
          #
          label = self.safe_string(response, 'label')
          if label is not None:
              feedback = self.id + ' ' + body
              self.throw_exactly_matched_exception(self.exceptions['exact'], label, feedback)
              raise ExchangeError(feedback)
  