text: # -*- coding: utf-8 -*-
  
  # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
  
  from ccxt.async_support.base.exchange import Exchange
  
  # -----------------------------------------------------------------------------
  
  try:
      basestring  # Python 3
  except NameError:
      basestring = str  # Python 2
  import json
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import PermissionDenied
  from ccxt.base.errors import ArgumentsRequired
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import RateLimitExceeded
  from ccxt.base.errors import InvalidNonce
  from ccxt.base.decimal_to_precision import TICK_SIZE
  from ccxt.base.precise import Precise
  
  
  class bybit(Exchange):
  
      def describe(self):
          return self.deep_extend(super(bybit, self).describe(), {
              'id': 'bybit',
              'name': 'Bybit',
              'countries': ['VG'],  # British Virgin Islands
              'version': 'v2',
              'userAgent': None,
              'rateLimit': 100,
              'hostname': 'bybit.com',  # bybit.com, bytick.com
              'has': {
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'CORS': True,
                  'createOrder': True,
                  'editOrder': True,
                  'fetchBalance': True,
                  'fetchClosedOrders': True,
                  'fetchDeposits': True,
                  'fetchFundingRate': True,
                  'fetchIndexOHLCV': True,
                  'fetchLedger': True,
                  'fetchMarkets': True,
                  'fetchMarkOHLCV': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchOrders': True,
                  'fetchOrderTrades': True,
                  'fetchPositions': True,
                  'fetchPremiumIndexOHLCV': True,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTime': True,
                  'fetchTrades': True,
                  'fetchTransactions': None,
                  'fetchWithdrawals': True,
                  'setMarginMode': True,
                  'setLeverage': True,
              },
              'timeframes': {
                  '1m': '1',
                  '3m': '3',
                  '5m': '5',
                  '15m': '15',
                  '30m': '30',
                  '1h': '60',
                  '2h': '120',
                  '4h': '240',
                  '6h': '360',
                  '12h': '720',
                  '1d': 'D',
                  '1w': 'W',
                  '1M': 'M',
                  '1y': 'Y',
              },
              'urls': {
                  'test': {
                      'spot': 'https://api-testnet.{hostname}',
                      'futures': 'https://api-testnet.{hostname}',
                      'v2': 'https://api-testnet.{hostname}',
                      'public': 'https://api-testnet.{hostname}',
                      'private': 'https://api-testnet.{hostname}',
                  },
                  'logo': 'https://user-images.githubusercontent.com/51840849/76547799-daff5b80-649e-11ea-87fb-3be9bac08954.jpg',
                  'api': {
                      'spot': 'https://api.{hostname}',
                      'futures': 'https://api.{hostname}',
                      'v2': 'https://api.{hostname}',
                      'public': 'https://api.{hostname}',
                      'private': 'https://api.{hostname}',
                  },
                  'www': 'https://www.bybit.com',
                  'doc': [
                      'https://bybit-exchange.github.io/docs/inverse/',
                      'https://bybit-exchange.github.io/docs/linear/',
                      'https://github.com/bybit-exchange',
                  ],
                  'fees': 'https://help.bybit.com/hc/en-us/articles/360039261154',
                  'referral': 'https://www.bybit.com/app/register?ref=X7Prm',
              },
              'api': {
                  'spot': {
                      'public': {
                          'get': [
                              'symbols',
                          ],
                      },
                      'quote': {
                          'get': [
                              'depth',
                              'depth/merged',
                              'trades',
                              'kline',
                              'ticker/24hr',
                              'ticker/price',
                              'ticker/book_ticker',
                          ],
                      },
                      'private': {
                          'get': [
                              'order',
                              'open-orders',
                              'history-orders',
                              'myTrades',
                              'account',
                              'time',
                          ],
                          'post': [
                              'order',
                          ],
                          'delete': [
                              'order',
                              'order/fast',
                          ],
                      },
                      'order': {
                          'delete': [
                              'batch-cancel',
                              'batch-fast-cancel',
                              'batch-cancel-by-ids',
                          ],
                      },
                  },
                  'futures': {
                      'private': {
                          'get': [
                              'order/list',
                              'order',
                              'stop-order/list',
                              'stop-order',
                              'position/list',
                              'execution/list',
                              'trade/closed-pnl/list',
                          ],
                          'post': [
                              'order/create',
                              'order/cancel',
                              'order/cancelAll',
                              'order/replace',
                              'stop-order/create',
                              'stop-order/cancel',
                              'stop-order/cancelAll',
                              'stop-order/replace',
                              'position/change-position-margin',
                              'position/trading-stop',
                              'position/leverage/save',
                              'position/switch-mode',
                              'position/switch-isolated',
                              'position/risk-limit',
                          ],
                      },
                  },
                  'v2': {
                      'public': {
                          'get': [
                              'orderBook/L2',
                              'kline/list',
                              'tickers',
                              'trading-records',
                              'symbols',
                              'liq-records',
                              'mark-price-kline',
                              'index-price-kline',
                              'premium-index-kline',
                              'open-interest',
                              'big-deal',
                              'account-ratio',
                              'time',
                              'announcement',
                              'funding/prev-funding-rate',
                              'risk-limit/list',
                          ],
                      },
                      'private': {
                          'get': [
                              'order/list',
                              'order',
                              'stop-order/list',
                              'stop-order',
                              'position/list',
                              'execution/list',
                              'trade/closed-pnl/list',
                              'funding/prev-funding-rate',
                              'funding/prev-funding',
                              'funding/predicted-funding',
                              'account/api-key',
                              'account/lcp',
                              'wallet/balance',
                              'wallet/fund/records',
                              'wallet/withdraw/list',
                              'exchange-order/list',
                          ],
                          'post': [
                              'order/create',
                              'order/cancel',
                              'order/cancelAll',
                              'order/replace',
                              'stop-order/create',
                              'stop-order/cancel',
                              'stop-order/cancelAll',
                              'stop-order/replace',
                              'position/change-position-margin',
                              'position/trading-stop',
                              'position/leverage/save',
                              'position/switch-mode',
                              'position/switch-isolated',
                              'position/risk-limit',
                          ],
                      },
                  },
                  'public': {
                      'linear': {
                          'get': [
                              'kline',
                              'recent-trading-records',
                              'funding/prev-funding-rate',
                              'mark-price-kline',
                              'index-price-kline',
                              'premium-index-kline',
                              'risk-limit',
                          ],
                      },
                  },
                  'private': {
                      'linear': {
                          'get': [
                              'order/list',
                              'order/search',
                              'stop-order/list',
                              'stop-order/search',
                              'position/list',
                              'trade/execution/list',
                              'trade/closed-pnl/list',
                              'funding/predicted-funding',
                              'funding/prev-funding',
                          ],
                          'post': [
                              'order/create',
                              'order/cancel',
                              'order/cancel-all',
                              'order/replace',
                              'stop-order/create',
                              'stop-order/cancel',
                              'stop-order/cancel-all',
                              'stop-order/replace',
                              'position/set-auto-add-margin',
                              'position/switch-isolated',
                              'tpsl/switch-mode',
                              'position/add-margin',
                              'position/set-leverage',
                              'position/trading-stop',
                              'position/set-risk',
                          ],
                      },
                  },
              },
              'httpExceptions': {
                  '403': RateLimitExceeded,  # Forbidden -- You request too many times
              },
              'exceptions': {
                  'exact': {
                      '10001': BadRequest,  # parameter error
                      '10002': InvalidNonce,  # request expired, check your timestamp and recv_window
                      '10003': AuthenticationError,  # Invalid apikey
                      '10004': AuthenticationError,  # invalid sign
                      '10005': PermissionDenied,  # permission denied for current apikey
                      '10006': RateLimitExceeded,  # too many requests
                      '10007': AuthenticationError,  # api_key not found in your request parameters
                      '10010': PermissionDenied,  # request ip mismatch
                      '10017': BadRequest,  # request path not found or request method is invalid
                      '10018': RateLimitExceeded,  # exceed ip rate limit
                      '20001': OrderNotFound,  # Order not exists
                      '20003': InvalidOrder,  # missing parameter side
                      '20004': InvalidOrder,  # invalid parameter side
                      '20005': InvalidOrder,  # missing parameter symbol
                      '20006': InvalidOrder,  # invalid parameter symbol
                      '20007': InvalidOrder,  # missing parameter order_type
                      '20008': InvalidOrder,  # invalid parameter order_type
                      '20009': InvalidOrder,  # missing parameter qty
                      '20010': InvalidOrder,  # qty must be greater than 0
                      '20011': InvalidOrder,  # qty must be an integer
                      '20012': InvalidOrder,  # qty must be greater than zero and less than 1 million
                      '20013': InvalidOrder,  # missing parameter price
                      '20014': InvalidOrder,  # price must be greater than 0
                      '20015': InvalidOrder,  # missing parameter time_in_force
                      '20016': InvalidOrder,  # invalid value for parameter time_in_force
                      '20017': InvalidOrder,  # missing parameter order_id
                      '20018': InvalidOrder,  # invalid date format
                      '20019': InvalidOrder,  # missing parameter stop_px
                      '20020': InvalidOrder,  # missing parameter base_price
                      '20021': InvalidOrder,  # missing parameter stop_order_id
                      '20022': BadRequest,  # missing parameter leverage
                      '20023': BadRequest,  # leverage must be a number
                      '20031': BadRequest,  # leverage must be greater than zero
                      '20070': BadRequest,  # missing parameter margin
                      '20071': BadRequest,  # margin must be greater than zero
                      '20084': BadRequest,  # order_id or order_link_id is required
                      '30001': BadRequest,  # order_link_id is repeated
                      '30003': InvalidOrder,  # qty must be more than the minimum allowed
                      '30004': InvalidOrder,  # qty must be less than the maximum allowed
                      '30005': InvalidOrder,  # price exceeds maximum allowed
                      '30007': InvalidOrder,  # price exceeds minimum allowed
                      '30008': InvalidOrder,  # invalid order_type
                      '30009': ExchangeError,  # no position found
                      '30010': InsufficientFunds,  # insufficient wallet balance
                      '30011': PermissionDenied,  # operation not allowed as position is undergoing liquidation
                      '30012': PermissionDenied,  # operation not allowed as position is undergoing ADL
                      '30013': PermissionDenied,  # position is in liq or adl status
                      '30014': InvalidOrder,  # invalid closing order, qty should not greater than size
                      '30015': InvalidOrder,  # invalid closing order, side should be opposite
                      '30016': ExchangeError,  # TS and SL must be cancelled first while closing position
                      '30017': InvalidOrder,  # estimated fill price cannot be lower than current Buy liq_price
                      '30018': InvalidOrder,  # estimated fill price cannot be higher than current Sell liq_price
                      '30019': InvalidOrder,  # cannot attach TP/SL params for non-zero position when placing non-opening position order
                      '30020': InvalidOrder,  # position already has TP/SL params
                      '30021': InvalidOrder,  # cannot afford estimated position_margin
                      '30022': InvalidOrder,  # estimated buy liq_price cannot be higher than current mark_price
                      '30023': InvalidOrder,  # estimated sell liq_price cannot be lower than current mark_price
                      '30024': InvalidOrder,  # cannot set TP/SL/TS for zero-position
                      '30025': InvalidOrder,  # trigger price should bigger than 10% of last price
                      '30026': InvalidOrder,  # price too high
                      '30027': InvalidOrder,  # price set for Take profit should be higher than Last Traded Price
                      '30028': InvalidOrder,  # price set for Stop loss should be between Liquidation price and Last Traded Price
                      '30029': InvalidOrder,  # price set for Stop loss should be between Last Traded Price and Liquidation price
                      '30030': InvalidOrder,  # price set for Take profit should be lower than Last Traded Price
                      '30031': InsufficientFunds,  # insufficient available balance for order cost
                      '30032': InvalidOrder,  # order has been filled or cancelled
                      '30033': RateLimitExceeded,  # The number of stop orders exceeds maximum limit allowed
                      '30034': OrderNotFound,  # no order found
                      '30035': RateLimitExceeded,  # too fast to cancel
                      '30036': ExchangeError,  # the expected position value after order execution exceeds the current risk limit
                      '30037': InvalidOrder,  # order already cancelled
                      '30041': ExchangeError,  # no position found
                      '30042': InsufficientFunds,  # insufficient wallet balance
                      '30043': InvalidOrder,  # operation not allowed as position is undergoing liquidation
                      '30044': InvalidOrder,  # operation not allowed as position is undergoing AD
                      '30045': InvalidOrder,  # operation not allowed as position is not normal status
                      '30049': InsufficientFunds,  # insufficient available balance
                      '30050': ExchangeError,  # any adjustments made will trigger immediate liquidation
                      '30051': ExchangeError,  # due to risk limit, cannot adjust leverage
                      '30052': ExchangeError,  # leverage can not less than 1
                      '30054': ExchangeError,  # position margin is invalid
                      '30057': ExchangeError,  # requested quantity of contracts exceeds risk limit
                      '30063': ExchangeError,  # reduce-only rule not satisfied
                      '30067': InsufficientFunds,  # insufficient available balance
                      '30068': ExchangeError,  # exit value must be positive
                      '30074': InvalidOrder,  # can't create the stop order, because you expect the order will be triggered when the LastPrice(or IndexPrice、 MarkPrice, determined by trigger_by) is raising to stop_px, but the LastPrice(or IndexPrice、 MarkPrice) is already equal to or greater than stop_px, please adjust base_price or stop_px
                      '30075': InvalidOrder,  # can't create the stop order, because you expect the order will be triggered when the LastPrice(or IndexPrice、 MarkPrice, determined by trigger_by) is falling to stop_px, but the LastPrice(or IndexPrice、 MarkPrice) is already equal to or less than stop_px, please adjust base_price or stop_px
                      '33004': AuthenticationError,  # apikey already expired
                      '34026': ExchangeError,  # the limit is no change
                  },
                  'broad': {
                      'unknown orderInfo': OrderNotFound,  # {"ret_code":-1,"ret_msg":"unknown orderInfo","ext_code":"","ext_info":"","result":null,"time_now":"1584030414.005545","rate_limit_status":99,"rate_limit_reset_ms":1584030414003,"rate_limit":100}
                      'invalid api_key': AuthenticationError,  # {"ret_code":10003,"ret_msg":"invalid api_key","ext_code":"","ext_info":"","result":null,"time_now":"1599547085.415797"}
                  },
              },
              'precisionMode': TICK_SIZE,
              'options': {
                  'marketTypes': {
                      'BTC/USDT': 'linear',
                      'ETH/USDT': 'linear',
                      'BNB/USDT': 'linear',
                      'ADA/USDT': 'linear',
                      'DOGE/USDT': 'linear',
                      'XRP/USDT': 'linear',
                      'DOT/USDT': 'linear',
                      'UNI/USDT': 'linear',
                      'BCH/USDT': 'linear',
                      'LTC/USDT': 'linear',
                      'SOL/USDT': 'linear',
                      'LINK/USDT': 'linear',
                      'MATIC/USDT': 'linear',
                      'ETC/USDT': 'linear',
                      'FIL/USDT': 'linear',
                      'EOS/USDT': 'linear',
                      'AAVE/USDT': 'linear',
                      'XTZ/USDT': 'linear',
                      'SUSHI/USDT': 'linear',
                      'XEM/USDT': 'linear',
                      'BTC/USD': 'inverse',
                      'ETH/USD': 'inverse',
                      'EOS/USD': 'inverse',
                      'XRP/USD': 'inverse',
                  },
                  'defaultType': 'linear',  # linear, inverse, futures
                  'code': 'BTC',
                  'cancelAllOrders': {
                      # 'method': 'v2PrivatePostOrderCancelAll',  # v2PrivatePostStopOrderCancelAll
                  },
                  'recvWindow': 5 * 1000,  # 5 sec default
                  'timeDifference': 0,  # the difference between system clock and exchange server clock
                  'adjustForTimeDifference': False,  # controls the adjustment logic upon instantiation
              },
              'fees': {
                  'trading': {
                      'tierBased': False,
                      'percentage': True,
                      'taker': 0.00075,
                      'maker': -0.00025,
                  },
                  'funding': {
                      'tierBased': False,
                      'percentage': False,
                      'withdraw': {},
                      'deposit': {},
                  },
              },
          })
  
      def nonce(self):
          return self.milliseconds() - self.options['timeDifference']
  
      async def load_time_difference(self, params={}):
          serverTime = await self.fetch_time(params)
          after = self.milliseconds()
          self.options['timeDifference'] = after - serverTime
          return self.options['timeDifference']
  
      async def fetch_time(self, params={}):
          response = await self.v2PublicGetTime(params)
          #
          #     {
          #         ret_code: 0,
          #         ret_msg: 'OK',
          #         ext_code: '',
          #         ext_info: '',
          #         result: {},
          #         time_now: '1583933682.448826'
          #     }
          #
          return self.safe_timestamp(response, 'time_now')
  
      async def fetch_markets(self, params={}):
          if self.options['adjustForTimeDifference']:
              await self.load_time_difference()
          response = await self.v2PublicGetSymbols(params)
          #
          #     {
          #         "ret_code":0,
          #         "ret_msg":"OK",
          #         "ext_code":"",
          #         "ext_info":"",
          #         "result":[
          #             {
          #                 "name":"BTCUSD",
          #                 "alias":"BTCUSD",
          #                 "status":"Trading",
          #                 "base_currency":"BTC",
          #                 "quote_currency":"USD",
          #                 "price_scale":2,
          #                 "taker_fee":"0.00075",
          #                 "maker_fee":"-0.00025",
          #                 "leverage_filter":{"min_leverage":1,"max_leverage":100,"leverage_step":"0.01"},
          #                 "price_filter":{"min_price":"0.5","max_price":"999999.5","tick_size":"0.5"},
          #                 "lot_size_filter":{"max_trading_qty":1000000,"min_trading_qty":1,"qty_step":1}
          #             },
          #             {
          #                 "name":"BTCUSDT",
          #                 "alias":"BTCUSDT",
          #                 "status":"Trading",
          #                 "base_currency":"BTC",
          #                 "quote_currency":"USDT",
          #                 "price_scale":2,
          #                 "taker_fee":"0.00075",
          #                 "maker_fee":"-0.00025",
          #                 "leverage_filter":{"min_leverage":1,"max_leverage":100,"leverage_step":"0.01"},
          #                 "price_filter":{"min_price":"0.5","max_price":"999999.5","tick_size":"0.5"},
          #                 "lot_size_filter":{"max_trading_qty":100,"min_trading_qty":0.001,"qty_step":0.001}
          #             },
          #         ],
          #         "time_now":"1610539664.818033"
          #     }
          #
          markets = self.safe_value(response, 'result', [])
          options = self.safe_value(self.options, 'fetchMarkets', {})
          linearQuoteCurrencies = self.safe_value(options, 'linear', {'USDT': True})
          result = []
          for i in range(0, len(markets)):
              market = markets[i]
              id = self.safe_string_2(market, 'name', 'symbol')
              baseId = self.safe_string(market, 'base_currency')
              quoteId = self.safe_string(market, 'quote_currency')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              linear = (quote in linearQuoteCurrencies)
              inverse = not linear
              symbol = base + '/' + quote
              baseQuote = base + quote
              type = 'swap'
              if baseQuote != id:
                  symbol = id
                  type = 'futures'
              lotSizeFilter = self.safe_value(market, 'lot_size_filter', {})
              priceFilter = self.safe_value(market, 'price_filter', {})
              precision = {
                  'amount': self.safe_number(lotSizeFilter, 'qty_step'),
                  'price': self.safe_number(priceFilter, 'tick_size'),
              }
              leverage = self.safe_value(market, 'leverage_filter', {})
              status = self.safe_string(market, 'status')
              active = None
              if status is not None:
                  active = (status == 'Trading')
              spot = (type == 'spot')
              swap = (type == 'swap')
              futures = (type == 'futures')
              option = (type == 'option')
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'active': active,
                  'precision': precision,
                  'taker': self.safe_number(market, 'taker_fee'),
                  'maker': self.safe_number(market, 'maker_fee'),
                  'type': type,
                  'spot': spot,
                  'swap': swap,
                  'futures': futures,
                  'option': option,
                  'linear': linear,
                  'inverse': inverse,
                  'limits': {
                      'amount': {
                          'min': self.safe_number(lotSizeFilter, 'min_trading_qty'),
                          'max': self.safe_number(lotSizeFilter, 'max_trading_qty'),
                      },
                      'price': {
                          'min': self.safe_number(priceFilter, 'min_price'),
                          'max': self.safe_number(priceFilter, 'max_price'),
                      },
                      'cost': {
                          'min': None,
                          'max': None,
                      },
                      'leverage': {
                          'max': self.safe_number(leverage, 'max_leverage', 1),
                      },
                  },
                  'info': market,
              })
          return result
  
      def parse_ticker(self, ticker, market=None):
          #
          # fetchTicker
          #
          #     {
          #         symbol: 'BTCUSD',
          #         bid_price: '7680',
          #         ask_price: '7680.5',
          #         last_price: '7680.00',
          #         last_tick_direction: 'MinusTick',
          #         prev_price_24h: '7870.50',
          #         price_24h_pcnt: '-0.024204',
          #         high_price_24h: '8035.00',
          #         low_price_24h: '7671.00',
          #         prev_price_1h: '7780.00',
          #         price_1h_pcnt: '-0.012853',
          #         mark_price: '7683.27',
          #         index_price: '7682.74',
          #         open_interest: 188829147,
          #         open_value: '23670.06',
          #         total_turnover: '25744224.90',
          #         turnover_24h: '102997.83',
          #         total_volume: 225448878806,
          #         volume_24h: 809919408,
          #         funding_rate: '0.0001',
          #         predicted_funding_rate: '0.0001',
          #         next_funding_time: '2020-03-12T00:00:00Z',
          #         countdown_hour: 7
          #     }
          #
          timestamp = None
          marketId = self.safe_string(ticker, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          last = self.safe_number(ticker, 'last_price')
          open = self.safe_number(ticker, 'prev_price_24h')
          percentage = self.safe_number(ticker, 'price_24h_pcnt')
          if percentage is not None:
              percentage *= 100
          change = None
          average = None
          if (last is not None) and (open is not None):
              change = last - open
              average = self.sum(open, last) / 2
          baseVolume = self.safe_number(ticker, 'turnover_24h')
          quoteVolume = self.safe_number(ticker, 'volume_24h')
          vwap = self.vwap(baseVolume, quoteVolume)
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_number(ticker, 'high_price_24h'),
              'low': self.safe_number(ticker, 'low_price_24h'),
              'bid': self.safe_number(ticker, 'bid_price'),
              'bidVolume': None,
              'ask': self.safe_number(ticker, 'ask_price'),
              'askVolume': None,
              'vwap': vwap,
              'open': open,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': change,
              'percentage': percentage,
              'average': average,
              'baseVolume': baseVolume,
              'quoteVolume': quoteVolume,
              'info': ticker,
          }
  
      async def fetch_ticker(self, symbol, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          response = await self.v2PublicGetTickers(self.extend(request, params))
          #
          #     {
          #         ret_code: 0,
          #         ret_msg: 'OK',
          #         ext_code: '',
          #         ext_info: '',
          #         result: [
          #             {
          #                 symbol: 'BTCUSD',
          #                 bid_price: '7680',
          #                 ask_price: '7680.5',
          #                 last_price: '7680.00',
          #                 last_tick_direction: 'MinusTick',
          #                 prev_price_24h: '7870.50',
          #                 price_24h_pcnt: '-0.024204',
          #                 high_price_24h: '8035.00',
          #                 low_price_24h: '7671.00',
          #                 prev_price_1h: '7780.00',
          #                 price_1h_pcnt: '-0.012853',
          #                 mark_price: '7683.27',
          #                 index_price: '7682.74',
          #                 open_interest: 188829147,
          #                 open_value: '23670.06',
          #                 total_turnover: '25744224.90',
          #                 turnover_24h: '102997.83',
          #                 total_volume: 225448878806,
          #                 volume_24h: 809919408,
          #                 funding_rate: '0.0001',
          #                 predicted_funding_rate: '0.0001',
          #                 next_funding_time: '2020-03-12T00:00:00Z',
          #                 countdown_hour: 7
          #             }
          #         ],
          #         time_now: '1583948195.818255'
          #     }
          #
          result = self.safe_value(response, 'result', [])
          first = self.safe_value(result, 0)
          timestamp = self.safe_timestamp(response, 'time_now')
          ticker = self.parse_ticker(first, market)
          ticker['timestamp'] = timestamp
          ticker['datetime'] = self.iso8601(timestamp)
          return ticker
  
      async def fetch_tickers(self, symbols=None, params={}):
          await self.load_markets()
          response = await self.v2PublicGetTickers(params)
          #
          #     {
          #         ret_code: 0,
          #         ret_msg: 'OK',
          #         ext_code: '',
          #         ext_info: '',
          #         result: [
          #             {
          #                 symbol: 'BTCUSD',
          #                 bid_price: '7680',
          #                 ask_price: '7680.5',
          #                 last_price: '7680.00',
          #                 last_tick_direction: 'MinusTick',
          #                 prev_price_24h: '7870.50',
          #                 price_24h_pcnt: '-0.024204',
          #                 high_price_24h: '8035.00',
          #                 low_price_24h: '7671.00',
          #                 prev_price_1h: '7780.00',
          #                 price_1h_pcnt: '-0.012853',
          #                 mark_price: '7683.27',
          #                 index_price: '7682.74',
          #                 open_interest: 188829147,
          #                 open_value: '23670.06',
          #                 total_turnover: '25744224.90',
          #                 turnover_24h: '102997.83',
          #                 total_volume: 225448878806,
          #                 volume_24h: 809919408,
          #                 funding_rate: '0.0001',
          #                 predicted_funding_rate: '0.0001',
          #                 next_funding_time: '2020-03-12T00:00:00Z',
          #                 countdown_hour: 7
          #             }
          #         ],
          #         time_now: '1583948195.818255'
          #     }
          #
          result = self.safe_value(response, 'result', [])
          tickers = {}
          for i in range(0, len(result)):
              ticker = self.parse_ticker(result[i])
              symbol = ticker['symbol']
              tickers[symbol] = ticker
          return self.filter_by_array(tickers, 'symbol', symbols)
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          # inverse perpetual BTC/USD
          #
          #     {
          #         symbol: 'BTCUSD',
          #         interval: '1',
          #         open_time: 1583952540,
          #         open: '7760.5',
          #         high: '7764',
          #         low: '7757',
          #         close: '7763.5',
          #         volume: '1259766',
          #         turnover: '162.32773718999994'
          #     }
          #
          # linear perpetual BTC/USDT
          #
          #     {
          #         "id":143536,
          #         "symbol":"BTCUSDT",
          #         "period":"15",
          #         "start_at":1587883500,
          #         "volume":1.035,
          #         "open":7540.5,
          #         "high":7541,
          #         "low":7540.5,
          #         "close":7541
          #     }
          #
          return [
              self.safe_timestamp_2(ohlcv, 'open_time', 'start_at'),
              self.safe_number(ohlcv, 'open'),
              self.safe_number(ohlcv, 'high'),
              self.safe_number(ohlcv, 'low'),
              self.safe_number(ohlcv, 'close'),
              self.safe_number_2(ohlcv, 'turnover', 'volume'),
          ]
  
      async def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          await self.load_markets()
          market = self.market(symbol)
          price = self.safe_string(params, 'price')
          params = self.omit(params, 'price')
          request = {
              'symbol': market['id'],
              'interval': self.timeframes[timeframe],
          }
          duration = self.parse_timeframe(timeframe)
          now = self.seconds()
          if since is None:
              if limit is None:
                  raise ArgumentsRequired(self.id + ' fetchOHLCV() requires a since argument or a limit argument')
              else:
                  request['from'] = now - limit * duration
          else:
              request['from'] = int(since / 1000)
          if limit is not None:
              request['limit'] = limit  # max 200, default 200
          method = 'v2PublicGetKlineList'
          if price == 'mark':
              method = 'v2PublicGetMarkPriceKline'
          elif price == 'index':
              method = 'v2PublicGetIndexPriceKline'
          elif price == 'premiumIndex':
              method = 'v2PublicGetPremiumIndexKline'
          elif market['linear']:
              method = 'publicLinearGetKline'
          response = await getattr(self, method)(self.extend(request, params))
          #
          # inverse perpetual BTC/USD
          #
          #     {
          #         ret_code: 0,
          #         ret_msg: 'OK',
          #         ext_code: '',
          #         ext_info: '',
          #         result: [
          #             {
          #                 symbol: 'BTCUSD',
          #                 interval: '1',
          #                 open_time: 1583952540,
          #                 open: '7760.5',
          #                 high: '7764',
          #                 low: '7757',
          #                 close: '7763.5',
          #                 volume: '1259766',
          #                 turnover: '162.32773718999994'
          #             },
          #         ],
          #         time_now: '1583953082.397330'
          #     }
          #
          # linear perpetual BTC/USDT
          #
          #     {
          #         "ret_code":0,
          #         "ret_msg":"OK",
          #         "ext_code":"",
          #         "ext_info":"",
          #         "result":[
          #             {
          #                 "id":143536,
          #                 "symbol":"BTCUSDT",
          #                 "period":"15",
          #                 "start_at":1587883500,
          #                 "volume":1.035,
          #                 "open":7540.5,
          #                 "high":7541,
          #                 "low":7540.5,
          #                 "close":7541
          #             }
          #         ],
          #         "time_now":"1587884120.168077"
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.parse_ohlcvs(result, market, timeframe, since, limit)
  
      async def fetch_funding_rate(self, symbol, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          method = 'v2PublicGetFundingPrevFundingRate'
          response = await getattr(self, method)(self.extend(request, params))
          #
          # {
          #     "ret_code": 0,
          #     "ret_msg": "ok",
          #     "ext_code": "",
          #     "result": {
          #         "symbol": "BTCUSD",
          #         "funding_rate": "0.00010000",
          #         "funding_rate_timestamp": 1577433600
          #     },
          #     "ext_info": null,
          #     "time_now": "1577445586.446797",
          #     "rate_limit_status": 119,
          #     "rate_limit_reset_ms": 1577445586454,
          #     "rate_limit": 120
          # }
          #
          result = self.safe_value(response, 'result')
          nextFundingRate = self.safe_number(result, 'funding_rate')
          previousFundingTime = self.safe_integer(result, 'funding_rate_timestamp') * 1000
          nextFundingTime = previousFundingTime + (8 * 3600000)
          currentTime = self.milliseconds()
          return {
              'info': result,
              'symbol': symbol,
              'markPrice': None,
              'indexPrice': None,
              'interestRate': None,
              'estimatedSettlePrice': None,
              'timestamp': currentTime,
              'datetime': self.iso8601(currentTime),
              'previousFundingRate': None,
              'nextFundingRate': nextFundingRate,
              'previousFundingTimestamp': previousFundingTime,
              'nextFundingTimestamp': nextFundingTime,
              'previousFundingDatetime': self.iso8601(previousFundingTime),
              'nextFundingDatetime': self.iso8601(nextFundingTime),
          }
  
      async def fetch_index_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          if since is None and limit is None:
              raise ArgumentsRequired(self.id + ' fetchIndexOHLCV() requires a since argument or a limit argument')
          request = {
              'price': 'index',
          }
          return await self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params))
  
      async def fetch_mark_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          if since is None and limit is None:
              raise ArgumentsRequired(self.id + ' fetchMarkOHLCV() requires a since argument or a limit argument')
          request = {
              'price': 'mark',
          }
          return await self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params))
  
      async def fetch_premium_index_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          if since is None and limit is None:
              raise ArgumentsRequired(self.id + ' fetchPremiumIndexOHLCV() requires a since argument or a limit argument')
          request = {
              'price': 'premiumIndex',
          }
          return await self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params))
  
      def parse_trade(self, trade, market=None):
          #
          # fetchTrades(public)
          #
          #     {
          #         id: 43785688,
          #         symbol: 'BTCUSD',
          #         price: 7786,
          #         qty: 67,
          #         side: 'Sell',
          #         time: '2020-03-11T19:18:30.123Z'
          #     }
          #
          # fetchMyTrades, fetchOrderTrades(private)
          #
          #     {
          #         "closed_size": 0,
          #         "cross_seq": 277136382,
          #         "exec_fee": "0.0000001",
          #         "exec_id": "256e5ef8-abfe-5772-971b-f944e15e0d68",
          #         "exec_price": "8178.5",
          #         "exec_qty": 1,
          #         # the docs say the exec_time field is "abandoned" now
          #         # the user should use "trade_time_ms"
          #         "exec_time": "1571676941.70682",
          #         "exec_type": "Trade",  #Exec Type Enum
          #         "exec_value": "0.00012227",
          #         "fee_rate": "0.00075",
          #         "last_liquidity_ind": "RemovedLiquidity",  #Liquidity Enum
          #         "leaves_qty": 0,
          #         "nth_fill": 2,
          #         "order_id": "7ad50cb1-9ad0-4f74-804b-d82a516e1029",
          #         "order_link_id": "",
          #         "order_price": "8178",
          #         "order_qty": 1,
          #         "order_type": "Market",  #Order Type Enum
          #         "side": "Buy",  #Side Enum
          #         "symbol": "BTCUSD",  #Symbol Enum
          #         "user_id": 1,
          #         "trade_time_ms": 1577480599000
          #     }
          #
          id = self.safe_string_2(trade, 'id', 'exec_id')
          marketId = self.safe_string(trade, 'symbol')
          market = self.safe_market(marketId, market)
          symbol = market['symbol']
          amountString = self.safe_string_2(trade, 'qty', 'exec_qty')
          priceString = self.safe_string_2(trade, 'exec_price', 'price')
          cost = self.safe_number(trade, 'exec_value')
          amount = self.parse_number(amountString)
          price = self.parse_number(priceString)
          if cost is None:
              cost = self.parse_number(Precise.string_mul(priceString, amountString))
          timestamp = self.parse8601(self.safe_string(trade, 'time'))
          if timestamp is None:
              timestamp = self.safe_integer(trade, 'trade_time_ms')
          side = self.safe_string_lower(trade, 'side')
          lastLiquidityInd = self.safe_string(trade, 'last_liquidity_ind')
          takerOrMaker = 'maker' if (lastLiquidityInd == 'AddedLiquidity') else 'taker'
          feeCost = self.safe_number(trade, 'exec_fee')
          fee = None
          if feeCost is not None:
              feeCurrencyCode = market['base'] if market['inverse'] else market['quote']
              fee = {
                  'cost': feeCost,
                  'currency': feeCurrencyCode,
                  'rate': self.safe_number(trade, 'fee_rate'),
              }
          return {
              'id': id,
              'info': trade,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'order': self.safe_string(trade, 'order_id'),
              'type': self.safe_string_lower(trade, 'order_type'),
              'side': side,
              'takerOrMaker': takerOrMaker,
              'price': price,
              'amount': amount,
              'cost': cost,
              'fee': fee,
          }
  
      async def fetch_trades(self, symbol, since=None, limit=None, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
              # 'from': 123,  # from id
          }
          if limit is not None:
              request['count'] = limit  # default 500, max 1000
          method = 'publicLinearGetRecentTradingRecords' if market['linear'] else 'v2PublicGetTradingRecords'
          response = await getattr(self, method)(self.extend(request, params))
          #
          #     {
          #         ret_code: 0,
          #         ret_msg: 'OK',
          #         ext_code: '',
          #         ext_info: '',
          #         result: [
          #             {
          #                 id: 43785688,
          #                 symbol: 'BTCUSD',
          #                 price: 7786,
          #                 qty: 67,
          #                 side: 'Sell',
          #                 time: '2020-03-11T19:18:30.123Z'
          #             },
          #         ],
          #         time_now: '1583954313.393362'
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.parse_trades(result, market, since, limit)
  
      def parse_order_book(self, orderbook, symbol, timestamp=None, bidsKey='Buy', asksKey='Sell', priceKey='price', amountKey='size'):
          bids = []
          asks = []
          for i in range(0, len(orderbook)):
              bidask = orderbook[i]
              side = self.safe_string(bidask, 'side')
              if side == 'Buy':
                  bids.append(self.parse_bid_ask(bidask, priceKey, amountKey))
              elif side == 'Sell':
                  asks.append(self.parse_bid_ask(bidask, priceKey, amountKey))
              else:
                  raise ExchangeError(self.id + ' parseOrderBook encountered an unrecognized bidask format: ' + self.json(bidask))
          return {
              'symbol': symbol,
              'bids': self.sort_by(bids, 0, True),
              'asks': self.sort_by(asks, 0),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'nonce': None,
          }
  
      async def fetch_order_book(self, symbol, limit=None, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          response = await self.v2PublicGetOrderBookL2(self.extend(request, params))
          #
          #     {
          #         ret_code: 0,
          #         ret_msg: 'OK',
          #         ext_code: '',
          #         ext_info: '',
          #         result: [
          #             {symbol: 'BTCUSD', price: '7767.5', size: 677956, side: 'Buy'},
          #             {symbol: 'BTCUSD', price: '7767', size: 580690, side: 'Buy'},
          #             {symbol: 'BTCUSD', price: '7766.5', size: 475252, side: 'Buy'},
          #             {symbol: 'BTCUSD', price: '7768', size: 330847, side: 'Sell'},
          #             {symbol: 'BTCUSD', price: '7768.5', size: 97159, side: 'Sell'},
          #             {symbol: 'BTCUSD', price: '7769', size: 6508, side: 'Sell'},
          #         ],
          #         time_now: '1583954829.874823'
          #     }
          #
          result = self.safe_value(response, 'result', [])
          timestamp = self.safe_timestamp(response, 'time_now')
          return self.parse_order_book(result, symbol, timestamp, 'Buy', 'Sell', 'price', 'size')
  
      async def fetch_balance(self, params={}):
          await self.load_markets()
          request = {}
          coin = self.safe_string(params, 'coin')
          code = self.safe_string(params, 'code')
          if coin is not None:
              request['coin'] = coin
          elif code is not None:
              currency = self.currency(code)
              request['coin'] = currency['id']
          response = await self.v2PrivateGetWalletBalance(self.extend(request, params))
          #
          #     {
          #         ret_code: 0,
          #         ret_msg: 'OK',
          #         ext_code: '',
          #         ext_info: '',
          #         result: {
          #             BTC: {
          #                 equity: 0,
          #                 available_balance: 0,
          #                 used_margin: 0,
          #                 order_margin: 0,
          #                 position_margin: 0,
          #                 occ_closing_fee: 0,
          #                 occ_funding_fee: 0,
          #                 wallet_balance: 0,
          #                 realised_pnl: 0,
          #                 unrealised_pnl: 0,
          #                 cum_realised_pnl: 0,
          #                 given_cash: 0,
          #                 service_cash: 0
          #             }
          #         },
          #         time_now: '1583937810.370020',
          #         rate_limit_status: 119,
          #         rate_limit_reset_ms: 1583937810367,
          #         rate_limit: 120
          #     }
          #
          result = {
              'info': response,
          }
          balances = self.safe_value(response, 'result', {})
          currencyIds = list(balances.keys())
          for i in range(0, len(currencyIds)):
              currencyId = currencyIds[i]
              balance = balances[currencyId]
              code = self.safe_currency_code(currencyId)
              account = self.account()
              account['free'] = self.safe_string(balance, 'available_balance')
              account['used'] = self.safe_string(balance, 'used_margin')
              account['total'] = self.safe_string(balance, 'equity')
              result[code] = account
          return self.parse_balance(result)
  
      def parse_order_status(self, status):
          statuses = {
              # basic orders
              'Created': 'open',
              'Rejected': 'rejected',  # order is triggered but failed upon being placed
              'New': 'open',
              'PartiallyFilled': 'open',
              'Filled': 'closed',
              'Cancelled': 'canceled',
              'PendingCancel': 'canceling',  # the engine has received the cancellation but there is no guarantee that it will be successful
              # conditional orders
              'Active': 'open',  # order is triggered and placed successfully
              'Untriggered': 'open',  # order waits to be triggered
              'Triggered': 'closed',  # order is triggered
              # 'Cancelled': 'canceled',  # order is cancelled
              # 'Rejected': 'rejected',  # order is triggered but fail to be placed
              'Deactivated': 'canceled',  # conditional order was cancelled before triggering
          }
          return self.safe_string(statuses, status, status)
  
      def parse_time_in_force(self, timeInForce):
          timeInForces = {
              'GoodTillCancel': 'GTC',
              'ImmediateOrCancel': 'IOC',
              'FillOrKill': 'FOK',
              'PostOnly': 'PO',
          }
          return self.safe_string(timeInForces, timeInForce, timeInForce)
  
      def parse_order(self, order, market=None):
          #
          # createOrder
          #
          #     {
          #         "user_id": 1,
          #         "order_id": "335fd977-e5a5-4781-b6d0-c772d5bfb95b",
          #         "symbol": "BTCUSD",
          #         "side": "Buy",
          #         "order_type": "Limit",
          #         "price": 8800,
          #         "qty": 1,
          #         "time_in_force": "GoodTillCancel",
          #         "order_status": "Created",
          #         "last_exec_time": 0,
          #         "last_exec_price": 0,
          #         "leaves_qty": 1,
          #         "cum_exec_qty": 0,  # in contracts, where 1 contract = 1 quote currency unit(USD for inverse contracts)
          #         "cum_exec_value": 0,  # in contract's underlying currency(BTC for inverse contracts)
          #         "cum_exec_fee": 0,
          #         "reject_reason": "",
          #         "order_link_id": "",
          #         "created_at": "2019-11-30T11:03:43.452Z",
          #         "updated_at": "2019-11-30T11:03:43.455Z"
          #     }
          #
          # fetchOrder
          #
          #     {
          #         "user_id" : 599946,
          #         "symbol" : "BTCUSD",
          #         "side" : "Buy",
          #         "order_type" : "Limit",
          #         "price" : "7948",
          #         "qty" : 10,
          #         "time_in_force" : "GoodTillCancel",
          #         "order_status" : "Filled",
          #         "ext_fields" : {
          #             "o_req_num" : -1600687220498,
          #             "xreq_type" : "x_create"
          #         },
          #         "last_exec_time" : "1588150113.968422",
          #         "last_exec_price" : "7948",
          #         "leaves_qty" : 0,
          #         "leaves_value" : "0",
          #         "cum_exec_qty" : 10,
          #         "cum_exec_value" : "0.00125817",
          #         "cum_exec_fee" : "-0.00000031",
          #         "reject_reason" : "",
          #         "cancel_type" : "",
          #         "order_link_id" : "",
          #         "created_at" : "2020-04-29T08:45:24.399146Z",
          #         "updated_at" : "2020-04-29T08:48:33.968422Z",
          #         "order_id" : "dd2504b9-0157-406a-99e1-efa522373944"
          #     }
          #
          # conditional order
          #
          #     {
          #         "user_id":##,
          #         "symbol":"BTCUSD",
          #         "side":"Buy",
          #         "order_type":"Market",
          #         "price":0,
          #         "qty":10,
          #         "time_in_force":"GoodTillCancel",
          #         "stop_order_type":"Stop",
          #         "trigger_by":"LastPrice",
          #         "base_price":11833,
          #         "order_status":"Untriggered",
          #         "ext_fields":{
          #             "stop_order_type":"Stop",
          #             "trigger_by":"LastPrice",
          #             "base_price":11833,
          #             "expected_direction":"Rising",
          #             "trigger_price":12400,
          #             "close_on_trigger":true,
          #             "op_from":"api",
          #             "remark":"x.x.x.x",
          #             "o_req_num":0
          #         },
          #         "leaves_qty":10,
          #         "leaves_value":0.00080645,
          #         "reject_reason":null,
          #         "cross_seq":-1,
          #         "created_at":"2020-08-21T09:18:48.000Z",
          #         "updated_at":"2020-08-21T09:18:48.000Z",
          #         "trigger_price":12400,
          #         "stop_order_id":"3f3b54b1-3379-42c7-8510-44f4d9915be0"
          #     }
          #
          marketId = self.safe_string(order, 'symbol')
          market = self.safe_market(marketId, market)
          symbol = market['symbol']
          feeCurrency = None
          timestamp = self.parse8601(self.safe_string(order, 'created_at'))
          id = self.safe_string_2(order, 'order_id', 'stop_order_id')
          type = self.safe_string_lower(order, 'order_type')
          price = self.safe_number(order, 'price')
          if price == 0.0:
              price = None
          average = self.safe_number(order, 'average_price')
          amount = self.safe_number(order, 'qty')
          cost = self.safe_number(order, 'cum_exec_value')
          filled = self.safe_number(order, 'cum_exec_qty')
          remaining = self.safe_number(order, 'leaves_qty')
          marketTypes = self.safe_value(self.options, 'marketTypes', {})
          marketType = self.safe_string(marketTypes, symbol)
          if market is not None:
              if marketType == 'linear':
                  feeCurrency = market['quote']
              else:
                  feeCurrency = market['base']
          lastTradeTimestamp = self.safe_timestamp(order, 'last_exec_time')
          if lastTradeTimestamp == 0:
              lastTradeTimestamp = None
          status = self.parse_order_status(self.safe_string_2(order, 'order_status', 'stop_order_status'))
          side = self.safe_string_lower(order, 'side')
          feeCost = self.safe_number(order, 'cum_exec_fee')
          fee = None
          if feeCost is not None:
              feeCost = abs(feeCost)
              fee = {
                  'cost': feeCost,
                  'currency': feeCurrency,
              }
          clientOrderId = self.safe_string(order, 'order_link_id')
          if (clientOrderId is not None) and (len(clientOrderId) < 1):
              clientOrderId = None
          timeInForce = self.parse_time_in_force(self.safe_string(order, 'time_in_force'))
          stopPrice = self.safe_number_2(order, 'trigger_price', 'stop_px')
          postOnly = (timeInForce == 'PO')
          return self.safe_order({
              'info': order,
              'id': id,
              'clientOrderId': clientOrderId,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': lastTradeTimestamp,
              'symbol': symbol,
              'type': type,
              'timeInForce': timeInForce,
              'postOnly': postOnly,
              'side': side,
              'price': price,
              'stopPrice': stopPrice,
              'amount': amount,
              'cost': cost,
              'average': average,
              'filled': filled,
              'remaining': remaining,
              'status': status,
              'fee': fee,
              'trades': None,
          })
  
      async def fetch_order(self, id, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
              # 'order_link_id': 'string',  # one of order_id, stop_order_id or order_link_id is required
              # regular orders ---------------------------------------------
              # 'order_id': id,  # one of order_id or order_link_id is required for regular orders
              # conditional orders ---------------------------------------------
              # 'stop_order_id': id,  # one of stop_order_id or order_link_id is required for conditional orders
          }
          method = None
          if market['swap']:
              if market['linear']:
                  method = 'privateLinearGetOrderSearch'
              elif market['inverse']:
                  method = 'v2PrivateGetOrder'
          elif market['futures']:
              method = 'futuresPrivateGetOrder'
          stopOrderId = self.safe_string(params, 'stop_order_id')
          if stopOrderId is None:
              orderLinkId = self.safe_string(params, 'order_link_id')
              if orderLinkId is None:
                  request['order_id'] = id
          else:
              if market['swap']:
                  if market['linear']:
                      method = 'privateLinearGetStopOrderSearch'
                  elif market['inverse']:
                      method = 'v2PrivateGetStopOrder'
              elif market['futures']:
                  method = 'futuresPrivateGetStopOrder'
          response = await getattr(self, method)(self.extend(request, params))
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "OK",
          #         "ext_code": "",
          #         "ext_info": "",
          #         "result": {
          #             "user_id": 1,
          #             "symbol": "BTCUSD",
          #             "side": "Sell",
          #             "order_type": "Limit",
          #             "price": "8083",
          #             "qty": 10,
          #             "time_in_force": "GoodTillCancel",
          #             "order_status": "New",
          #             "ext_fields": {"o_req_num": -308787, "xreq_type": "x_create", "xreq_offset": 4154640},
          #             "leaves_qty": 10,
          #             "leaves_value": "0.00123716",
          #             "cum_exec_qty": 0,
          #             "reject_reason": "",
          #             "order_link_id": "",
          #             "created_at": "2019-10-21T07:28:19.396246Z",
          #             "updated_at": "2019-10-21T07:28:19.396246Z",
          #             "order_id": "efa44157-c355-4a98-b6d6-1d846a936b93"
          #         },
          #         "time_now": "1571651135.291930",
          #         "rate_limit_status": 99,  # The remaining number of accesses in one minute
          #         "rate_limit_reset_ms": 1580885703683,
          #         "rate_limit": 100
          #     }
          #
          # conditional orders
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "OK",
          #         "ext_code": "",
          #         "ext_info": "",
          #         "result": {
          #             "user_id": 1,
          #             "symbol": "BTCUSD",
          #             "side": "Buy",
          #             "order_type": "Limit",
          #             "price": "8000",
          #             "qty": 1,
          #             "time_in_force": "GoodTillCancel",
          #             "order_status": "Untriggered",
          #             "ext_fields": {},
          #             "leaves_qty": 1,
          #             "leaves_value": "0.00013333",
          #             "cum_exec_qty": 0,
          #             "cum_exec_value": null,
          #             "cum_exec_fee": null,
          #             "reject_reason": "",
          #             "order_link_id": "",
          #             "created_at": "2019-12-27T19:56:24.052194Z",
          #             "updated_at": "2019-12-27T19:56:24.052194Z",
          #             "order_id": "378a1bbc-a93a-4e75-87f4-502ea754ba36"
          #         },
          #         "time_now": "1577476584.386958",
          #         "rate_limit_status": 99,
          #         "rate_limit_reset_ms": 1580885703683,
          #         "rate_limit": 100
          #     }
          #
          result = self.safe_value(response, 'result')
          return self.parse_order(result, market)
  
      async def create_order(self, symbol, type, side, amount, price=None, params={}):
          await self.load_markets()
          market = self.market(symbol)
          qty = self.amount_to_precision(symbol, amount)
          if market['inverse']:
              qty = int(qty)
          else:
              qty = float(qty)
          request = {
              # orders ---------------------------------------------------------
              'side': self.capitalize(side),
              'symbol': market['id'],
              'order_type': self.capitalize(type),
              'qty': qty,  # order quantity in USD, integer only
              # 'price': float(self.price_to_precision(symbol, price)),  # required for limit orders
              'time_in_force': 'GoodTillCancel',  # ImmediateOrCancel, FillOrKill, PostOnly
              # 'take_profit': 123.45,  # take profit price, only take effect upon opening the position
              # 'stop_loss': 123.45,  # stop loss price, only take effect upon opening the position
              # 'reduce_only': False,  # reduce only, required for linear orders
              # when creating a closing order, bybit recommends a True value for
              # close_on_trigger to avoid failing due to insufficient available margin
              # 'close_on_trigger': False, required for linear orders
              # 'order_link_id': 'string',  # unique client order id, max 36 characters
              # conditional orders ---------------------------------------------
              # base_price is used to compare with the value of stop_px, to decide
              # whether your conditional order will be triggered by crossing trigger
              # price from upper side or lower side, mainly used to identify the
              # expected direction of the current conditional order
              # 'base_price': 123.45,  # required for conditional orders
              # 'stop_px': 123.45,  # trigger price, required for conditional orders
              # 'trigger_by': 'LastPrice',  # IndexPrice, MarkPrice
          }
          priceIsRequired = False
          if type == 'limit':
              priceIsRequired = True
          if priceIsRequired:
              if price is not None:
                  request['price'] = float(self.price_to_precision(symbol, price))
              else:
                  raise ArgumentsRequired(self.id + ' createOrder() requires a price argument for a ' + type + ' order')
          clientOrderId = self.safe_string_2(params, 'order_link_id', 'clientOrderId')
          if clientOrderId is not None:
              request['order_link_id'] = clientOrderId
              params = self.omit(params, ['order_link_id', 'clientOrderId'])
          stopPx = self.safe_value_2(params, 'stop_px', 'stopPrice')
          basePrice = self.safe_value(params, 'base_price')
          method = None
          if market['swap']:
              if market['linear']:
                  method = 'privateLinearPostOrderCreate'
                  request['reduce_only'] = False
                  request['close_on_trigger'] = False
              elif market['inverse']:
                  method = 'v2PrivatePostOrderCreate'
          elif market['futures']:
              method = 'futuresPrivatePostOrderCreate'
          if stopPx is not None:
              if basePrice is None:
                  raise ArgumentsRequired(self.id + ' createOrder() requires both the stop_px and base_price params for a conditional ' + type + ' order')
              else:
                  if market['swap']:
                      if market['linear']:
                          method = 'privateLinearPostStopOrderCreate'
                      elif market['inverse']:
                          method = 'v2PrivatePostStopOrderCreate'
                  elif market['futures']:
                      method = 'futuresPrivatePostStopOrderCreate'
                  request['stop_px'] = float(self.price_to_precision(symbol, stopPx))
                  request['base_price'] = float(self.price_to_precision(symbol, basePrice))
                  params = self.omit(params, ['stop_px', 'stopPrice', 'base_price'])
          elif basePrice is not None:
              raise ArgumentsRequired(self.id + ' createOrder() requires both the stop_px and base_price params for a conditional ' + type + ' order')
          response = await getattr(self, method)(self.extend(request, params))
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "OK",
          #         "ext_code": "",
          #         "ext_info": "",
          #         "result": {
          #             "user_id": 1,
          #             "order_id": "335fd977-e5a5-4781-b6d0-c772d5bfb95b",
          #             "symbol": "BTCUSD",
          #             "side": "Buy",
          #             "order_type": "Limit",
          #             "price": 8800,
          #             "qty": 1,
          #             "time_in_force": "GoodTillCancel",
          #             "order_status": "Created",
          #             "last_exec_time": 0,
          #             "last_exec_price": 0,
          #             "leaves_qty": 1,
          #             "cum_exec_qty": 0,
          #             "cum_exec_value": 0,
          #             "cum_exec_fee": 0,
          #             "reject_reason": "",
          #             "order_link_id": "",
          #             "created_at": "2019-11-30T11:03:43.452Z",
          #             "updated_at": "2019-11-30T11:03:43.455Z"
          #         },
          #         "time_now": "1575111823.458705",
          #         "rate_limit_status": 98,
          #         "rate_limit_reset_ms": 1580885703683,
          #         "rate_limit": 100
          #     }
          #
          # conditional orders
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "ok",
          #         "ext_code": "",
          #         "result": {
          #             "user_id": 1,
          #             "symbol": "BTCUSD",
          #             "side": "Buy",
          #             "order_type": "Limit",
          #             "price": 8000,
          #             "qty": 1,
          #             "time_in_force": "GoodTillCancel",
          #             "stop_order_type": "Stop",
          #             "trigger_by": "LastPrice",
          #             "base_price": 7000,
          #             "order_status": "Untriggered",
          #             "ext_fields": {
          #                 "stop_order_type": "Stop",
          #                 "trigger_by": "LastPrice",
          #                 "base_price": 7000,
          #                 "expected_direction": "Rising",
          #                 "trigger_price": 7500,
          #                 "op_from": "api",
          #                 "remark": "127.0.01",
          #                 "o_req_num": 0
          #             },
          #             "leaves_qty": 1,
          #             "leaves_value": 0.00013333,
          #             "reject_reason": null,
          #             "cross_seq": -1,
          #             "created_at": "2019-12-27T12:48:24.000Z",
          #             "updated_at": "2019-12-27T12:48:24.000Z",
          #             "stop_px": 7500,
          #             "stop_order_id": "a85cd1c0-a9a4-49d3-a1bd-bab5ebe946d5"
          #         },
          #         "ext_info": null,
          #         "time_now": "1577450904.327654",
          #         "rate_limit_status": 99,
          #         "rate_limit_reset_ms": 1577450904335,
          #         "rate_limit": "100"
          #     }
          #
          result = self.safe_value(response, 'result')
          return self.parse_order(result, market)
  
      async def edit_order(self, id, symbol, type, side, amount=None, price=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' editOrder() requires an symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          request = {
              # 'order_id': id,  # only for non-conditional orders
              'symbol': market['id'],
              # 'p_r_qty': self.amount_to_precision(symbol, amount),  # new order quantity, optional
              # 'p_r_price' self.priceToprecision(symbol, price),  # new order price, optional
              # ----------------------------------------------------------------
              # conditional orders
              # 'stop_order_id': id,  # only for conditional orders
              # 'p_r_trigger_price': 123.45,  # new trigger price also known as stop_px
          }
          method = None
          if market['swap']:
              if market['linear']:
                  method = 'privateLinearPostOrderReplace'
              elif market['inverse']:
                  method = 'v2PrivatePostOrderReplace'
          elif market['futures']:
              method = 'futuresPrivatePostOrderReplace'
          stopOrderId = self.safe_string(params, 'stop_order_id')
          if stopOrderId is not None:
              if market['swap']:
                  if market['linear']:
                      method = 'privateLinearPostStopOrderReplace'
                  elif market['inverse']:
                      method = 'v2PrivatePostStopOrderReplace'
              elif market['futures']:
                  method = 'futuresPrivatePostStopOrderReplace'
              request['stop_order_id'] = stopOrderId
              params = self.omit(params, ['stop_order_id'])
          else:
              request['order_id'] = id
          if amount is not None:
              qty = self.amount_to_precision(symbol, amount)
              if market['inverse']:
                  qty = int(qty)
              else:
                  qty = float(qty)
              request['p_r_qty'] = qty
          if price is not None:
              request['p_r_price'] = float(self.price_to_precision(symbol, price))
          response = await getattr(self, method)(self.extend(request, params))
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "ok",
          #         "ext_code": "",
          #         "result": {"order_id": "efa44157-c355-4a98-b6d6-1d846a936b93"},
          #         "time_now": "1539778407.210858",
          #         "rate_limit_status": 99,  # remaining number of accesses in one minute
          #         "rate_limit_reset_ms": 1580885703683,
          #         "rate_limit": 100
          #     }
          #
          # conditional orders
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "ok",
          #         "ext_code": "",
          #         "result": {"stop_order_id": "378a1bbc-a93a-4e75-87f4-502ea754ba36"},
          #         "ext_info": null,
          #         "time_now": "1577475760.604942",
          #         "rate_limit_status": 96,
          #         "rate_limit_reset_ms": 1577475760612,
          #         "rate_limit": "100"
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return {
              'info': response,
              'id': self.safe_string_2(result, 'order_id', 'stop_order_id'),
              'order_id': self.safe_string(result, 'order_id'),
              'stop_order_id': self.safe_string(result, 'stop_order_id'),
          }
  
      async def cancel_order(self, id, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
              # 'order_link_id': 'string',  # one of order_id, stop_order_id or order_link_id is required
              # regular orders ---------------------------------------------
              # 'order_id': id,  # one of order_id or order_link_id is required for regular orders
              # conditional orders ---------------------------------------------
              # 'stop_order_id': id,  # one of stop_order_id or order_link_id is required for conditional orders
          }
          method = None
          if market['swap']:
              if market['linear']:
                  method = 'privateLinearPostOrderCancel'
              elif market['inverse']:
                  method = 'v2PrivatePostOrderCancel'
          elif market['futures']:
              method = 'futuresPrivatePostOrderCancel'
          stopOrderId = self.safe_string(params, 'stop_order_id')
          if stopOrderId is None:
              orderLinkId = self.safe_string(params, 'order_link_id')
              if orderLinkId is None:
                  request['order_id'] = id
          else:
              if market['swap']:
                  if market['linear']:
                      method = 'privateLinearPostStopOrderCancel'
                  elif market['inverse']:
                      method = 'v2PrivatePostStopOrderCancel'
              elif market['futures']:
                  method = 'futuresPrivatePostStopOrderCancel'
          response = await getattr(self, method)(self.extend(request, params))
          result = self.safe_value(response, 'result', {})
          return self.parse_order(result, market)
  
      async def cancel_all_orders(self, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          options = self.safe_value(self.options, 'cancelAllOrders', {})
          defaultMethod = None
          if market['swap']:
              if market['linear']:
                  defaultMethod = 'privateLinearPostOrderCancelAll'
              elif market['inverse']:
                  defaultMethod = 'v2PrivatePostOrderCancelAll'
          elif market['futures']:
              defaultMethod = 'futuresPrivatePostOrderCancelAll'
          method = self.safe_string(options, 'method', defaultMethod)
          response = await getattr(self, method)(self.extend(request, params))
          result = self.safe_value(response, 'result', [])
          return self.parse_orders(result, market)
  
      async def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'order_id': 'string'
              # 'order_link_id': 'string',  # unique client order id, max 36 characters
              # 'symbol': market['id'],  # default BTCUSD
              # 'order': 'desc',  # asc
              # 'page': 1,
              # 'limit': 20,  # max 50
              # 'order_status': 'Created,New'
              # conditional orders ---------------------------------------------
              # 'stop_order_id': 'string',
              # 'stop_order_status': 'Untriggered',
          }
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['symbol'] = market['id']
          if limit is not None:
              request['limit'] = limit
          options = self.safe_value(self.options, 'fetchOrders', {})
          defaultType = self.safe_string(self.options, 'defaultType', 'linear')
          marketTypes = self.safe_value(self.options, 'marketTypes', {})
          marketType = self.safe_string(marketTypes, symbol, defaultType)
          defaultMethod = None
          marketDefined = (market is not None)
          linear = (marketDefined and market['linear']) or (marketType == 'linear')
          inverse = (marketDefined and market['swap'] and market['inverse']) or (marketType == 'inverse')
          futures = (marketDefined and market['futures']) or (marketType == 'futures')
          if linear:
              defaultMethod = 'privateLinearGetOrderList'
          elif inverse:
              defaultMethod = 'v2PrivateGetOrderList'
          elif futures:
              defaultMethod = 'futuresPrivateGetOrderList'
          query = params
          if ('stop_order_id' in params) or ('stop_order_status' in params):
              stopOrderStatus = self.safe_value(params, 'stop_order_status')
              if stopOrderStatus is not None:
                  if isinstance(stopOrderStatus, list):
                      stopOrderStatus = ','.join(stopOrderStatus)
                  request['stop_order_status'] = stopOrderStatus
                  query = self.omit(params, 'stop_order_status')
              if linear:
                  defaultMethod = 'privateLinearGetStopOrderList'
              elif inverse:
                  defaultMethod = 'v2PrivateGetStopOrderList'
              elif futures:
                  defaultMethod = 'futuresPrivateGetStopOrderList'
          method = self.safe_string(options, 'method', defaultMethod)
          response = await getattr(self, method)(self.extend(request, query))
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "ok",
          #         "ext_code": "",
          #         "result": {
          #             "current_page": 1,
          #             "last_page": 6,
          #             "data": [
          #                 {
          #                     "user_id": 1,
          #                     "symbol": "BTCUSD",
          #                     "side": "Sell",
          #                     "order_type": "Market",
          #                     "price": 7074,
          #                     "qty": 2,
          #                     "time_in_force": "ImmediateOrCancel",
          #                     "order_status": "Filled",
          #                     "ext_fields": {
          #                         "close_on_trigger": True,
          #                         "orig_order_type": "BLimit",
          #                         "prior_x_req_price": 5898.5,
          #                         "op_from": "pc",
          #                         "remark": "127.0.0.1",
          #                         "o_req_num": -34799032763,
          #                         "xreq_type": "x_create"
          #                     },
          #                     "last_exec_time": "1577448481.696421",
          #                     "last_exec_price": 7070.5,
          #                     "leaves_qty": 0,
          #                     "leaves_value": 0,
          #                     "cum_exec_qty": 2,
          #                     "cum_exec_value": 0.00028283,
          #                     "cum_exec_fee": 0.00002,
          #                     "reject_reason": "NoError",
          #                     "order_link_id": "",
          #                     "created_at": "2019-12-27T12:08:01.000Z",
          #                     "updated_at": "2019-12-27T12:08:01.000Z",
          #                     "order_id": "f185806b-b801-40ff-adec-52289370ed62"
          #                 }
          #             ]
          #         },
          #         "ext_info": null,
          #         "time_now": "1577448922.437871",
          #         "rate_limit_status": 98,
          #         "rate_limit_reset_ms": 1580885703683,
          #         "rate_limit": 100
          #     }
          #
          # conditional orders
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "ok",
          #         "ext_code": "",
          #         "result": {
          #             "current_page": 1,
          #             "last_page": 1,
          #             "data": [
          #                 {
          #                     "user_id": 1,
          #                     "stop_order_status": "Untriggered",
          #                     "symbol": "BTCUSD",
          #                     "side": "Buy",
          #                     "order_type": "Limit",
          #                     "price": 8000,
          #                     "qty": 1,
          #                     "time_in_force": "GoodTillCancel",
          #                     "stop_order_type": "Stop",
          #                     "trigger_by": "LastPrice",
          #                     "base_price": 7000,
          #                     "order_link_id": "",
          #                     "created_at": "2019-12-27T12:48:24.000Z",
          #                     "updated_at": "2019-12-27T12:48:24.000Z",
          #                     "stop_px": 7500,
          #                     "stop_order_id": "a85cd1c0-a9a4-49d3-a1bd-bab5ebe946d5"
          #                 },
          #             ]
          #         },
          #         "ext_info": null,
          #         "time_now": "1577451658.755468",
          #         "rate_limit_status": 599,
          #         "rate_limit_reset_ms": 1577451658762,
          #         "rate_limit": 600
          #     }
          #
          result = self.safe_value(response, 'result', {})
          data = self.safe_value(result, 'data', [])
          return self.parse_orders(data, market, since, limit)
  
      async def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          defaultStatuses = [
              'Rejected',
              'Filled',
              'Cancelled',
              # conditional orders
              # 'Active',
              # 'Triggered',
              # 'Cancelled',
              # 'Rejected',
              # 'Deactivated',
          ]
          options = self.safe_value(self.options, 'fetchClosedOrders', {})
          status = self.safe_value(options, 'order_status', defaultStatuses)
          if isinstance(status, list):
              status = ','.join(status)
          request = {}
          stopOrderStatus = self.safe_value(params, 'stop_order_status')
          if stopOrderStatus is None:
              request['order_status'] = status
          else:
              request['stop_order_status'] = stopOrderStatus
          return await self.fetch_orders(symbol, since, limit, self.extend(request, params))
  
      async def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          defaultStatuses = [
              'Created',
              'New',
              'PartiallyFilled',
              'PendingCancel',
              # conditional orders
              # 'Untriggered',
          ]
          options = self.safe_value(self.options, 'fetchOpenOrders', {})
          status = self.safe_value(options, 'order_status', defaultStatuses)
          if isinstance(status, list):
              status = ','.join(status)
          request = {}
          stopOrderStatus = self.safe_value(params, 'stop_order_status')
          if stopOrderStatus is None:
              request['order_status'] = status
          else:
              request['stop_order_status'] = stopOrderStatus
          return await self.fetch_orders(symbol, since, limit, self.extend(request, params))
  
      async def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
          request = {
              'order_id': id,
          }
          return await self.fetch_my_trades(symbol, since, limit, self.extend(request, params))
  
      async def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'order_id': 'f185806b-b801-40ff-adec-52289370ed62',  # if not provided will return user's trading records
              # 'symbol': market['id'],
              # 'start_time': int(since / 1000),
              # 'page': 1,
              # 'limit' 20,  # max 50
          }
          market = None
          if symbol is None:
              orderId = self.safe_string(params, 'order_id')
              if orderId is None:
                  raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument or an order_id param')
              else:
                  request['order_id'] = orderId
                  params = self.omit(params, 'order_id')
          else:
              market = self.market(symbol)
              request['symbol'] = market['id']
          if since is not None:
              request['start_time'] = since
          if limit is not None:
              request['limit'] = limit  # default 20, max 50
          defaultType = self.safe_string(self.options, 'defaultType', 'linear')
          marketTypes = self.safe_value(self.options, 'marketTypes', {})
          marketType = self.safe_string(marketTypes, symbol, defaultType)
          marketDefined = (market is not None)
          linear = (marketDefined and market['linear']) or (marketType == 'linear')
          inverse = (marketDefined and market['swap'] and market['inverse']) or (marketType == 'inverse')
          futures = (marketDefined and market['futures']) or (marketType == 'futures')
          method = None
          if linear:
              method = 'privateLinearGetTradeExecutionList'
          elif inverse:
              method = 'v2PrivateGetExecutionList'
          elif futures:
              method = 'futuresPrivateGetExecutionList'
          response = await getattr(self, method)(self.extend(request, params))
          #
          # inverse
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "OK",
          #         "ext_code": "",
          #         "ext_info": "",
          #         "result": {
          #             "order_id": "Abandonednot !",  # Abandonednot !
          #             "trade_list": [
          #                 {
          #                     "closed_size": 0,
          #                     "cross_seq": 277136382,
          #                     "exec_fee": "0.0000001",
          #                     "exec_id": "256e5ef8-abfe-5772-971b-f944e15e0d68",
          #                     "exec_price": "8178.5",
          #                     "exec_qty": 1,
          #                     "exec_time": "1571676941.70682",
          #                     "exec_type": "Trade",  #Exec Type Enum
          #                     "exec_value": "0.00012227",
          #                     "fee_rate": "0.00075",
          #                     "last_liquidity_ind": "RemovedLiquidity",  #Liquidity Enum
          #                     "leaves_qty": 0,
          #                     "nth_fill": 2,
          #                     "order_id": "7ad50cb1-9ad0-4f74-804b-d82a516e1029",
          #                     "order_link_id": "",
          #                     "order_price": "8178",
          #                     "order_qty": 1,
          #                     "order_type": "Market",  #Order Type Enum
          #                     "side": "Buy",  #Side Enum
          #                     "symbol": "BTCUSD",  #Symbol Enum
          #                     "user_id": 1
          #                 }
          #             ]
          #         },
          #         "time_now": "1577483699.281488",
          #         "rate_limit_status": 118,
          #         "rate_limit_reset_ms": 1577483699244737,
          #         "rate_limit": 120
          #     }
          #
          # linear
          #
          #     {
          #         "ret_code":0,
          #         "ret_msg":"OK",
          #         "ext_code":"",
          #         "ext_info":"",
          #         "result":{
          #             "current_page":1,
          #             "data":[
          #                 {
          #                     "order_id":"b59418ec-14d4-4ef9-b9f4-721d5d576974",
          #                     "order_link_id":"",
          #                     "side":"Sell",
          #                     "symbol":"BTCUSDT",
          #                     "exec_id":"0327284d-faec-5191-bd89-acc5b4fafda9",
          #                     "price":0.5,
          #                     "order_price":0.5,
          #                     "order_qty":0.01,
          #                     "order_type":"Market",
          #                     "fee_rate":0.00075,
          #                     "exec_price":9709.5,
          #                     "exec_type":"Trade",
          #                     "exec_qty":0.01,
          #                     "exec_fee":0.07282125,
          #                     "exec_value":97.095,
          #                     "leaves_qty":0,
          #                     "closed_size":0.01,
          #                     "last_liquidity_ind":"RemovedLiquidity",
          #                     "trade_time":1591648052,
          #                     "trade_time_ms":1591648052861
          #                 }
          #             ]
          #         },
          #         "time_now":"1591736501.979264",
          #         "rate_limit_status":119,
          #         "rate_limit_reset_ms":1591736501974,
          #         "rate_limit":120
          #     }
          #
          result = self.safe_value(response, 'result', {})
          trades = self.safe_value_2(result, 'trade_list', 'data', [])
          return self.parse_trades(trades, market, since, limit)
  
      async def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'coin': currency['id'],
              # 'currency': currency['id'],  # alias
              # 'start_date': self.iso8601(since),
              # 'end_date': self.iso8601(till),
              'wallet_fund_type': 'Deposit',  # Deposit, Withdraw, RealisedPNL, Commission, Refund, Prize, ExchangeOrderWithdraw, ExchangeOrderDeposit
              # 'page': 1,
              # 'limit': 20,  # max 50
          }
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['coin'] = currency['id']
          if since is not None:
              request['start_date'] = self.ymd(since)
          if limit is not None:
              request['limit'] = limit
          response = await self.v2PrivateGetWalletFundRecords(self.extend(request, params))
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "ok",
          #         "ext_code": "",
          #         "result": {
          #             "data": [
          #                 {
          #                     "id": 234467,
          #                     "user_id": 1,
          #                     "coin": "BTC",
          #                     "wallet_id": 27913,
          #                     "type": "Realized P&L",
          #                     "amount": "-0.00000006",
          #                     "tx_id": "",
          #                     "address": "BTCUSD",
          #                     "wallet_balance": "0.03000330",
          #                     "exec_time": "2019-12-09T00:00:25.000Z",
          #                     "cross_seq": 0
          #                 }
          #             ]
          #         },
          #         "ext_info": null,
          #         "time_now": "1577481867.115552",
          #         "rate_limit_status": 119,
          #         "rate_limit_reset_ms": 1577481867122,
          #         "rate_limit": 120
          #     }
          #
          result = self.safe_value(response, 'result', {})
          data = self.safe_value(result, 'data', [])
          return self.parse_transactions(data, currency, since, limit, {'type': 'deposit'})
  
      async def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'coin': currency['id'],
              # 'start_date': self.iso8601(since),
              # 'end_date': self.iso8601(till),
              # 'status': 'Pending',  # ToBeConfirmed, UnderReview, Pending, Success, CancelByUser, Reject, Expire
              # 'page': 1,
              # 'limit': 20,  # max 50
          }
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['coin'] = currency['id']
          if since is not None:
              request['start_date'] = self.ymd(since)
          if limit is not None:
              request['limit'] = limit
          response = await self.v2PrivateGetWalletWithdrawList(self.extend(request, params))
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "ok",
          #         "ext_code": "",
          #         "result": {
          #             "data": [
          #                 {
          #                     "id": 137,
          #                     "user_id": 1,
          #                     "coin": "XRP",  # Coin Enum
          #                     "status": "Pending",  # Withdraw Status Enum
          #                     "amount": "20.00000000",
          #                     "fee": "0.25000000",
          #                     "address": "rH7H595XYEVTEHU2FySYsWnmfACBnZS9zM",
          #                     "tx_id": "",
          #                     "submited_at": "2019-06-11T02:20:24.000Z",
          #                     "updated_at": "2019-06-11T02:20:24.000Z"
          #                 },
          #             ],
          #             "current_page": 1,
          #             "last_page": 1
          #         },
          #         "ext_info": null,
          #         "time_now": "1577482295.125488",
          #         "rate_limit_status": 119,
          #         "rate_limit_reset_ms": 1577482295132,
          #         "rate_limit": 120
          #     }
          #
          result = self.safe_value(response, 'result', {})
          data = self.safe_value(result, 'data', [])
          return self.parse_transactions(data, currency, since, limit, {'type': 'withdrawal'})
  
      def parse_transaction_status(self, status):
          statuses = {
              'ToBeConfirmed': 'pending',
              'UnderReview': 'pending',
              'Pending': 'pending',
              'Success': 'ok',
              'CancelByUser': 'canceled',
              'Reject': 'rejected',
              'Expire': 'expired',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchWithdrawals
          #
          #     {
          #         "id": 137,
          #         "user_id": 1,
          #         "coin": "XRP",  # Coin Enum
          #         "status": "Pending",  # Withdraw Status Enum
          #         "amount": "20.00000000",
          #         "fee": "0.25000000",
          #         "address": "rH7H595XYEVTEHU2FySYsWnmfACBnZS9zM",
          #         "tx_id": "",
          #         "submited_at": "2019-06-11T02:20:24.000Z",
          #         "updated_at": "2019-06-11T02:20:24.000Z"
          #     }
          #
          # fetchDeposits ledger entries
          #
          #     {
          #         "id": 234467,
          #         "user_id": 1,
          #         "coin": "BTC",
          #         "wallet_id": 27913,
          #         "type": "Realized P&L",
          #         "amount": "-0.00000006",
          #         "tx_id": "",
          #         "address": "BTCUSD",
          #         "wallet_balance": "0.03000330",
          #         "exec_time": "2019-12-09T00:00:25.000Z",
          #         "cross_seq": 0
          #     }
          #
          currencyId = self.safe_string(transaction, 'coin')
          code = self.safe_currency_code(currencyId, currency)
          timestamp = self.parse8601(self.safe_string_2(transaction, 'submited_at', 'exec_time'))
          updated = self.parse8601(self.safe_string(transaction, 'updated_at'))
          status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
          address = self.safe_string(transaction, 'address')
          feeCost = self.safe_number(transaction, 'fee')
          type = self.safe_string_lower(transaction, 'type')
          fee = None
          if feeCost is not None:
              fee = {
                  'cost': feeCost,
                  'currency': code,
              }
          return {
              'info': transaction,
              'id': self.safe_string(transaction, 'id'),
              'txid': self.safe_string(transaction, 'tx_id'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'address': address,
              'addressTo': None,
              'addressFrom': None,
              'tag': None,
              'tagTo': None,
              'tagFrom': None,
              'type': type,
              'amount': self.safe_number(transaction, 'amount'),
              'currency': code,
              'status': status,
              'updated': updated,
              'fee': fee,
          }
  
      async def fetch_ledger(self, code=None, since=None, limit=None, params={}):
          await self.load_markets()
          request = {
              # 'coin': currency['id'],
              # 'currency': currency['id'],  # alias
              # 'start_date': self.iso8601(since),
              # 'end_date': self.iso8601(till),
              # 'wallet_fund_type': 'Deposit',  # Withdraw, RealisedPNL, Commission, Refund, Prize, ExchangeOrderWithdraw, ExchangeOrderDeposit
              # 'page': 1,
              # 'limit': 20,  # max 50
          }
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['coin'] = currency['id']
          if since is not None:
              request['start_date'] = self.ymd(since)
          if limit is not None:
              request['limit'] = limit
          response = await self.v2PrivateGetWalletFundRecords(self.extend(request, params))
          #
          #     {
          #         "ret_code": 0,
          #         "ret_msg": "ok",
          #         "ext_code": "",
          #         "result": {
          #             "data": [
          #                 {
          #                     "id": 234467,
          #                     "user_id": 1,
          #                     "coin": "BTC",
          #                     "wallet_id": 27913,
          #                     "type": "Realized P&L",
          #                     "amount": "-0.00000006",
          #                     "tx_id": "",
          #                     "address": "BTCUSD",
          #                     "wallet_balance": "0.03000330",
          #                     "exec_time": "2019-12-09T00:00:25.000Z",
          #                     "cross_seq": 0
          #                 }
          #             ]
          #         },
          #         "ext_info": null,
          #         "time_now": "1577481867.115552",
          #         "rate_limit_status": 119,
          #         "rate_limit_reset_ms": 1577481867122,
          #         "rate_limit": 120
          #     }
          #
          result = self.safe_value(response, 'result', {})
          data = self.safe_value(result, 'data', [])
          return self.parse_ledger(data, currency, since, limit)
  
      def parse_ledger_entry(self, item, currency=None):
          #
          #     {
          #         "id": 234467,
          #         "user_id": 1,
          #         "coin": "BTC",
          #         "wallet_id": 27913,
          #         "type": "Realized P&L",
          #         "amount": "-0.00000006",
          #         "tx_id": "",
          #         "address": "BTCUSD",
          #         "wallet_balance": "0.03000330",
          #         "exec_time": "2019-12-09T00:00:25.000Z",
          #         "cross_seq": 0
          #     }
          #
          currencyId = self.safe_string(item, 'coin')
          code = self.safe_currency_code(currencyId, currency)
          amount = self.safe_number(item, 'amount')
          after = self.safe_number(item, 'wallet_balance')
          direction = 'out' if (amount < 0) else 'in'
          before = None
          if after is not None and amount is not None:
              difference = amount if (direction == 'out') else -amount
              before = self.sum(after, difference)
          timestamp = self.parse8601(self.safe_string(item, 'exec_time'))
          type = self.parse_ledger_entry_type(self.safe_string(item, 'type'))
          id = self.safe_string(item, 'id')
          referenceId = self.safe_string(item, 'tx_id')
          return {
              'id': id,
              'currency': code,
              'account': self.safe_string(item, 'wallet_id'),
              'referenceAccount': None,
              'referenceId': referenceId,
              'status': None,
              'amount': amount,
              'before': before,
              'after': after,
              'fee': None,
              'direction': direction,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'type': type,
              'info': item,
          }
  
      def parse_ledger_entry_type(self, type):
          types = {
              'Deposit': 'transaction',
              'Withdraw': 'transaction',
              'RealisedPNL': 'trade',
              'Commission': 'fee',
              'Refund': 'cashback',
              'Prize': 'prize',  # ?
              'ExchangeOrderWithdraw': 'transaction',
              'ExchangeOrderDeposit': 'transaction',
          }
          return self.safe_string(types, type, type)
  
      async def fetch_positions(self, symbols=None, params={}):
          await self.load_markets()
          request = {}
          if isinstance(symbols, list):
              length = len(symbols)
              if length != 1:
                  raise ArgumentsRequired(self.id + ' fetchPositions takes an array with exactly one symbol')
              request['symbol'] = self.market_id(symbols[0])
          defaultType = self.safe_string(self.options, 'defaultType', 'linear')
          type = self.safe_string(params, 'type', defaultType)
          params = self.omit(params, 'type')
          response = None
          if type == 'linear':
              response = await self.privateLinearGetPositionList(self.extend(request, params))
          elif type == 'inverse':
              response = await self.v2PrivateGetPositionList(self.extend(request, params))
          elif type == 'inverseFuture':
              response = await self.futuresPrivateGetPositionList(self.extend(request, params))
          if (isinstance(response, basestring)) and self.is_json_encoded_object(response):
              response = json.loads(response)
          #
          #     {
          #         ret_code: 0,
          #         ret_msg: 'OK',
          #         ext_code: '',
          #         ext_info: '',
          #         result: [] or {} depending on the request
          #     }
          #
          return self.safe_value(response, 'result')
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          type = self.safe_string(api, 0)
          section = self.safe_string(api, 1)
          if type == 'spot':
              if section == 'public':
                  section = 'v1'
              else:
                  section += '/v1'
          url = self.implode_hostname(self.urls['api'][type])
          request = '/' + type + '/' + section + '/' + path
          if (type == 'spot') or (type == 'quote'):
              if params:
                  request += '?' + self.rawencode(params)
          elif section == 'public':
              if params:
                  request += '?' + self.rawencode(params)
          elif type == 'public':
              if params:
                  request += '?' + self.rawencode(params)
          else:
              self.check_required_credentials()
              timestamp = self.nonce()
              query = self.extend(params, {
                  'api_key': self.apiKey,
                  'recv_window': self.options['recvWindow'],
                  'timestamp': timestamp,
              })
              sortedQuery = self.keysort(query)
              auth = self.rawencode(sortedQuery)
              signature = self.hmac(self.encode(auth), self.encode(self.secret))
              if method == 'POST':
                  body = self.json(self.extend(query, {
                      'sign': signature,
                  }))
                  headers = {
                      'Content-Type': 'application/json',
                  }
              else:
                  request += '?' + self.urlencode(sortedQuery) + '&sign=' + signature
          url += request
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if not response:
              return  # fallback to default error handler
          #
          #     {
          #         ret_code: 10001,
          #         ret_msg: 'ReadMapCB: expect {or n, but found \u0000, error ' +
          #         'found in  #0 byte of ...||..., bigger context ' +
          #         '...||...',
          #         ext_code: '',
          #         ext_info: '',
          #         result: null,
          #         time_now: '1583934106.590436'
          #     }
          #
          errorCode = self.safe_string(response, 'ret_code')
          if errorCode != '0':
              feedback = self.id + ' ' + body
              self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
              self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
              raise ExchangeError(feedback)  # unknown message
  
      async def set_margin_mode(self, symbol, marginType, params={}):
          #
          # {
          #     "ret_code": 0,
          #     "ret_msg": "ok",
          #     "ext_code": "",
          #     "result": null,
          #     "ext_info": null,
          #     "time_now": "1577477968.175013",
          #     "rate_limit_status": 74,
          #     "rate_limit_reset_ms": 1577477968183,
          #     "rate_limit": 75
          # }
          #
          leverage = self.safe_value(params, 'leverage')
          if leverage is None:
              raise ArgumentsRequired(self.id + '.setMarginMode requires a leverage parameter')
          marginType = marginType.upper()
          if (marginType != 'ISOLATED') and (marginType != 'CROSSED'):
              raise BadRequest(self.id + ' marginType must be either isolated or crossed')
          await self.load_markets()
          market = self.market(symbol)
          method = None
          defaultType = self.safe_string(self.options, 'defaultType', 'linear')
          marketTypes = self.safe_value(self.options, 'marketTypes', {})
          marketType = self.safe_string(marketTypes, symbol, defaultType)
          linear = market['linear'] or (marketType == 'linear')
          inverse = (market['swap'] and market['inverse']) or (marketType == 'inverse')
          futures = market['futures'] or (marketType == 'futures')
          if linear:
              method = 'privateLinearPostPositionSwitchIsolated'
          elif inverse:
              method = 'v2PrivatePostPositionSwitchIsolated'
          elif futures:
              method = 'privateFuturesPostPositionSwitchIsolated'
          isIsolated = (marginType == 'ISOLATED')
          request = {
              'symbol': market['id'],
              'is_isolated': isIsolated,
              'buy_leverage': leverage,
              'sell_leverage': leverage,
          }
          return await getattr(self, method)(self.extend(request, params))
  
      async def set_leverage(self, leverage=None, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
          await self.load_markets()
          market = self.market(symbol)
          # WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
          # AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
          defaultType = self.safe_string(self.options, 'defaultType', 'linear')
          marketTypes = self.safe_value(self.options, 'marketTypes', {})
          marketType = self.safe_string(marketTypes, symbol, defaultType)
          linear = market['linear'] or (marketType == 'linear')
          inverse = (market['swap'] and market['inverse']) or (marketType == 'inverse')
          futures = market['futures'] or (marketType == 'futures')
          method = None
          if linear:
              method = 'privateLinearPostPositionSetLeverage'
          elif inverse:
              method = 'v2PrivatePostPositionLeverageSave'
          elif futures:
              method = 'privateFuturesPostPositionLeverageSave'
          buy_leverage = leverage
          sell_leverage = leverage
          if params['buy_leverage'] and params['sell_leverage'] and linear:
              buy_leverage = params['buy_leverage']
              sell_leverage = params['sell_leverage']
          elif not leverage:
              if linear:
                  raise ArgumentsRequired(self.id + ' setLeverage() requires either the parameter leverage or params["buy_leverage"] and params["sell_leverage"] for linear contracts')
              else:
                  raise ArgumentsRequired(self.id + ' setLeverage() requires parameter leverage for inverse and futures contracts')
          if (buy_leverage < 1) or (buy_leverage > 100) or (sell_leverage < 1) or (sell_leverage > 100):
              raise BadRequest(self.id + ' leverage should be between 1 and 100')
          request = {
              'symbol': market['id'],
              'leverage_only': True,
          }
          if not linear:
              request['leverage'] = buy_leverage
          else:
              request['buy_leverage'] = buy_leverage
              request['sell_leverage'] = sell_leverage
          return await getattr(self, method)(self.extend(request, params))
  