text: # -*- coding: utf-8 -*-
  
  # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
  
  from ccxt.base.exchange import Exchange
  
  # -----------------------------------------------------------------------------
  
  try:
      basestring  # Python 3
  except NameError:
      basestring = str  # Python 2
  import hashlib
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import PermissionDenied
  from ccxt.base.errors import ArgumentsRequired
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import BadSymbol
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import CancelPending
  from ccxt.base.errors import DuplicateOrderId
  from ccxt.base.errors import RateLimitExceeded
  from ccxt.base.errors import ExchangeNotAvailable
  from ccxt.base.decimal_to_precision import TICK_SIZE
  from ccxt.base.precise import Precise
  
  
  class ftx(Exchange):
  
      def describe(self):
          return self.deep_extend(super(ftx, self).describe(), {
              'id': 'ftx',
              'name': 'FTX',
              'countries': ['HK'],
              'rateLimit': 50,
              'certified': True,
              'pro': True,
              'hostname': 'ftx.com',  # or ftx.us
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/67149189-df896480-f2b0-11e9-8816-41593e17f9ec.jpg',
                  'www': 'https://ftx.com',
                  'api': {
                      'public': 'https://{hostname}',
                      'private': 'https://{hostname}',
                  },
                  'doc': 'https://github.com/ftexchange/ftx',
                  'fees': 'https://ftexchange.zendesk.com/hc/en-us/articles/360024479432-Fees',
                  'referral': {
                      'url': 'https://ftx.com/#a=ccxt',
                      'discount': 0.05,
                  },
              },
              'has': {
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'createOrder': True,
                  'editOrder': True,
                  'fetchBalance': True,
                  'fetchClosedOrders': False,
                  'fetchCurrencies': True,
                  'fetchDepositAddress': True,
                  'fetchDeposits': True,
                  'fetchFundingFees': False,
                  'fetchMarkets': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchOrders': True,
                  'fetchPositions': True,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTrades': True,
                  'fetchTradingFees': True,
                  'fetchWithdrawals': True,
                  'withdraw': True,
              },
              'timeframes': {
                  '15s': '15',
                  '1m': '60',
                  '5m': '300',
                  '15m': '900',
                  '1h': '3600',
                  '4h': '14400',
                  '1d': '86400',
              },
              'api': {
                  'public': {
                      'get': [
                          'coins',
                          'markets',
                          'markets/{market_name}',
                          'markets/{market_name}/orderbook',  # ?depth={depth}
                          'markets/{market_name}/trades',  # ?limit={limit}&start_time={start_time}&end_time={end_time}
                          'markets/{market_name}/candles',  # ?resolution={resolution}&limit={limit}&start_time={start_time}&end_time={end_time}
                          # futures
                          'futures',
                          'futures/{future_name}',
                          'futures/{future_name}/stats',
                          'funding_rates',
                          'indexes/{index_name}/weights',
                          'expired_futures',
                          'indexes/{market_name}/candles',  # ?resolution={resolution}&limit={limit}&start_time={start_time}&end_time={end_time}
                          # leverage tokens
                          'lt/tokens',
                          'lt/{token_name}',
                          # options
                          'options/requests',
                          'options/trades',
                          'stats/24h_options_volume',
                          'options/historical_volumes/BTC',
                          'options/open_interest/BTC',
                          'options/historical_open_interest/BTC',
                          # spot margin
                          'spot_margin/history',
                      ],
                  },
                  'private': {
                      'get': [
                          'account',
                          'positions',
                          'wallet/coins',
                          'wallet/balances',
                          'wallet/all_balances',
                          'wallet/deposit_address/{coin}',  # ?method={method}
                          'wallet/deposits',
                          'wallet/withdrawals',
                          'wallet/withdrawal_fee',
                          'wallet/airdrops',
                          'wallet/saved_addresses',
                          'orders',  # ?market={market}
                          'orders/history',  # ?market={market}
                          'orders/{order_id}',
                          'orders/by_client_id/{client_order_id}',
                          'conditional_orders',  # ?market={market}
                          'conditional_orders/{conditional_order_id}/triggers',
                          'conditional_orders/history',  # ?market={market}
                          'spot_margin/borrow_rates',
                          'spot_margin/lending_rates',
                          'spot_margin/borrow_summary',
                          'spot_margin/market_info',  # ?market={market}
                          'spot_margin/borrow_history',
                          'spot_margin/lending_history',
                          'spot_margin/offers',
                          'spot_margin/lending_info',
                          'fills',  # ?market={market}
                          'funding_payments',
                          # leverage tokens
                          'lt/balances',
                          'lt/creations',
                          'lt/redemptions',
                          # subaccounts
                          'subaccounts',
                          'subaccounts/{nickname}/balances',
                          # otc
                          'otc/quotes/{quoteId}',
                          # options
                          'options/my_requests',
                          'options/requests/{request_id}/quotes',
                          'options/my_quotes',
                          'options/account_info',
                          'options/positions',
                          'options/fills',
                          # staking
                          'staking/stakes',
                          'staking/unstake_requests',
                          'staking/balances',
                          'staking/staking_rewards',
                      ],
                      'post': [
                          'account/leverage',
                          'wallet/withdrawals',
                          'wallet/saved_addresses',
                          'orders',
                          'conditional_orders',
                          'orders/{order_id}/modify',
                          'orders/by_client_id/{client_order_id}/modify',
                          'conditional_orders/{order_id}/modify',
                          # spot margin
                          'spot_margin/offers',
                          # leverage tokens
                          'lt/{token_name}/create',
                          'lt/{token_name}/redeem',
                          # subaccounts
                          'subaccounts',
                          'subaccounts/update_name',
                          'subaccounts/transfer',
                          # otc
                          'otc/quotes/{quote_id}/accept',
                          'otc/quotes',
                          # options
                          'options/requests',
                          'options/requests/{request_id}/quotes',
                          'options/quotes/{quote_id}/accept',
                          # staking
                          'staking/unstake_requests',
                          'srm_stakes/stakes',
                      ],
                      'delete': [
                          'wallet/saved_addresses/{saved_address_id}',
                          'orders/{order_id}',
                          'orders/by_client_id/{client_order_id}',
                          'orders',
                          'conditional_orders/{order_id}',
                          # subaccounts
                          'subaccounts',
                          # options
                          'options/requests/{request_id}',
                          'options/quotes/{quote_id}',
                          # staking
                          'staking/unstake_requests/{request_id}',
                      ],
                  },
              },
              'fees': {
                  'trading': {
                      'tierBased': True,
                      'percentage': True,
                      'maker': 0.02 / 100,
                      'taker': 0.07 / 100,
                      'tiers': {
                          'taker': [
                              [0, 0.07 / 100],
                              [1000000, 0.06 / 100],
                              [5000000, 0.055 / 100],
                              [10000000, 0.05 / 100],
                              [15000000, 0.045 / 100],
                              [35000000, 0.04 / 100],
                          ],
                          'maker': [
                              [0, 0.02 / 100],
                              [1000000, 0.02 / 100],
                              [5000000, 0.015 / 100],
                              [10000000, 0.015 / 100],
                              [15000000, 0.01 / 100],
                              [35000000, 0.01 / 100],
                          ],
                      },
                  },
                  'funding': {
                      'withdraw': {},
                  },
              },
              'exceptions': {
                  'exact': {
                      'Please slow down': RateLimitExceeded,  # {"error":"Please slow down","success":false}
                      'Size too small for provide': InvalidOrder,  # {"error":"Size too small for provide","success":false}
                      'Not logged in': AuthenticationError,  # {"error":"Not logged in","success":false}
                      'Not enough balances': InsufficientFunds,  # {"error":"Not enough balances","success":false}
                      'InvalidPrice': InvalidOrder,  # {"error":"Invalid price","success":false}
                      'Size too small': InvalidOrder,  # {"error":"Size too small","success":false}
                      'Size too large': InvalidOrder,  # {"error":"Size too large","success":false}
                      'Missing parameter price': InvalidOrder,  # {"error":"Missing parameter price","success":false}
                      'Order not found': OrderNotFound,  # {"error":"Order not found","success":false}
                      'Order already closed': InvalidOrder,  # {"error":"Order already closed","success":false}
                      'Trigger price too high': InvalidOrder,  # {"error":"Trigger price too high","success":false}
                      'Trigger price too low': InvalidOrder,  # {"error":"Trigger price too low","success":false}
                      'Order already queued for cancellation': CancelPending,  # {"error":"Order already queued for cancellation","success":false}
                      'Duplicate client order ID': DuplicateOrderId,  # {"error":"Duplicate client order ID","success":false}
                      'Spot orders cannot be reduce-only': InvalidOrder,  # {"error":"Spot orders cannot be reduce-only","success":false}
                      'Invalid reduce-only order': InvalidOrder,  # {"error":"Invalid reduce-only order","success":false}
                  },
                  'broad': {
                      'Account does not have enough margin for order': InsufficientFunds,
                      'Invalid parameter': BadRequest,  # {"error":"Invalid parameter start_time","success":false}
                      'The requested URL was not found on the server': BadRequest,
                      'No such coin': BadRequest,
                      'No such future': BadSymbol,
                      'No such market': BadSymbol,
                      'Do not send more than': RateLimitExceeded,
                      'An unexpected error occurred': ExchangeNotAvailable,  # {"error":"An unexpected error occurred, please try again later(58BC21C795).","success":false}
                      'Please retry request': ExchangeNotAvailable,  # {"error":"Please retry request","success":false}
                      'Please try again': ExchangeNotAvailable,  # {"error":"Please try again","success":false}
                      'Try again': ExchangeNotAvailable,  # {"error":"Try again","success":false}
                      'Only have permissions for subaccount': PermissionDenied,  # {"success":false,"error":"Only have permissions for subaccount *sub_name*"}
                  },
              },
              'precisionMode': TICK_SIZE,
              'options': {
                  # support for canceling conditional orders
                  # https://github.com/ccxt/ccxt/issues/6669
                  'cancelOrder': {
                      'method': 'privateDeleteOrdersOrderId',  # privateDeleteConditionalOrdersOrderId
                  },
                  'fetchOpenOrders': {
                      'method': 'privateGetOrders',  # privateGetConditionalOrders
                  },
                  'fetchOrders': {
                      'method': 'privateGetOrdersHistory',  # privateGetConditionalOrdersHistory
                  },
                  'sign': {
                      'ftx.com': 'FTX',
                      'ftx.us': 'FTXUS',
                  },
              },
          })
  
      def fetch_currencies(self, params={}):
          response = self.publicGetCoins(params)
          currencies = self.safe_value(response, 'result', [])
          #
          #     {
          #         "success":true,
          #         "result": [
          #             {"id":"BTC","name":"Bitcoin"},
          #             {"id":"ETH","name":"Ethereum"},
          #             {"id":"ETHMOON","name":"10X Long Ethereum Token","underlying":"ETH"},
          #             {"id":"EOSBULL","name":"3X Long EOS Token","underlying":"EOS"},
          #         ],
          #     }
          #
          result = {}
          for i in range(0, len(currencies)):
              currency = currencies[i]
              id = self.safe_string(currency, 'id')
              code = self.safe_currency_code(id)
              name = self.safe_string(currency, 'name')
              result[code] = {
                  'id': id,
                  'code': code,
                  'info': currency,
                  'type': None,
                  'name': name,
                  'active': None,
                  'fee': None,
                  'precision': None,
                  'limits': {
                      'withdraw': {'min': None, 'max': None},
                      'amount': {'min': None, 'max': None},
                  },
              }
          return result
  
      def fetch_markets(self, params={}):
          response = self.publicGetMarkets(params)
          #
          #     {
          #         'success': True,
          #         "result": [
          #             {
          #                 "ask":170.37,
          #                 "baseCurrency":null,
          #                 "bid":170.31,
          #                 "change1h":-0.019001554672655036,
          #                 "change24h":-0.024841165359738997,
          #                 "changeBod":-0.03816406029469881,
          #                 "enabled":true,
          #                 "last":170.37,
          #                 "name":"ETH-PERP",
          #                 "price":170.37,
          #                 "priceIncrement":0.01,
          #                 "quoteCurrency":null,
          #                 "quoteVolume24h":7742164.59889,
          #                 "sizeIncrement":0.001,
          #                 "type":"future",
          #                 "underlying":"ETH",
          #                 "volumeUsd24h":7742164.59889
          #             },
          #             {
          #                 "ask":170.44,
          #                 "baseCurrency":"ETH",
          #                 "bid":170.41,
          #                 "change1h":-0.018485459257126403,
          #                 "change24h":-0.023825887743413515,
          #                 "changeBod":-0.037605872388481086,
          #                 "enabled":true,
          #                 "last":172.72,
          #                 "name":"ETH/USD",
          #                 "price":170.44,
          #                 "priceIncrement":0.01,
          #                 "quoteCurrency":"USD",
          #                 "quoteVolume24h":382802.0252,
          #                 "sizeIncrement":0.001,
          #                 "type":"spot",
          #                 "underlying":null,
          #                 "volumeUsd24h":382802.0252
          #             },
          #         ],
          #     }
          #
          result = []
          markets = self.safe_value(response, 'result', [])
          for i in range(0, len(markets)):
              market = markets[i]
              id = self.safe_string(market, 'name')
              baseId = self.safe_string_2(market, 'baseCurrency', 'underlying')
              quoteId = self.safe_string(market, 'quoteCurrency', 'USD')
              type = self.safe_string(market, 'type')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              # check if a market is a spot or future market
              symbol = self.safe_string(market, 'name') if (type == 'future') else (base + '/' + quote)
              active = self.safe_value(market, 'enabled')
              sizeIncrement = self.safe_number(market, 'sizeIncrement')
              priceIncrement = self.safe_number(market, 'priceIncrement')
              precision = {
                  'amount': sizeIncrement,
                  'price': priceIncrement,
              }
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'type': type,
                  'future': (type == 'future'),
                  'spot': (type == 'spot'),
                  'active': active,
                  'precision': precision,
                  'limits': {
                      'amount': {
                          'min': sizeIncrement,
                          'max': None,
                      },
                      'price': {
                          'min': priceIncrement,
                          'max': None,
                      },
                      'cost': {
                          'min': None,
                          'max': None,
                      },
                  },
                  'info': market,
              })
          return result
  
      def parse_ticker(self, ticker, market=None):
          #
          #     {
          #         "ask":171.29,
          #         "baseCurrency":null,  # base currency for spot markets
          #         "bid":171.24,
          #         "change1h":-0.0012244897959183673,
          #         "change24h":-0.031603346901854366,
          #         "changeBod":-0.03297013492914808,
          #         "enabled":true,
          #         "last":171.44,
          #         "name":"ETH-PERP",
          #         "price":171.29,
          #         "priceIncrement":0.01,
          #         "quoteCurrency":null,  # quote currency for spot markets
          #         "quoteVolume24h":8570651.12113,
          #         "sizeIncrement":0.001,
          #         "type":"future",
          #         "underlying":"ETH",  # null for spot markets
          #         "volumeUsd24h":8570651.12113,
          #     }
          #
          symbol = None
          marketId = self.safe_string(ticker, 'name')
          if marketId in self.markets_by_id:
              market = self.markets_by_id[marketId]
          else:
              type = self.safe_string(ticker, 'type')
              if type == 'future':
                  symbol = marketId
              else:
                  base = self.safe_currency_code(self.safe_string(ticker, 'baseCurrency'))
                  quote = self.safe_currency_code(self.safe_string(ticker, 'quoteCurrency'))
                  if (base is not None) and (quote is not None):
                      symbol = base + '/' + quote
          if (symbol is None) and (market is not None):
              symbol = market['symbol']
          last = self.safe_number(ticker, 'last')
          timestamp = self.safe_timestamp(ticker, 'time', self.milliseconds())
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_number(ticker, 'high'),
              'low': self.safe_number(ticker, 'low'),
              'bid': self.safe_number(ticker, 'bid'),
              'bidVolume': self.safe_number(ticker, 'bidSize'),
              'ask': self.safe_number(ticker, 'ask'),
              'askVolume': self.safe_number(ticker, 'askSize'),
              'vwap': None,
              'open': None,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': None,
              'percentage': self.safe_number(ticker, 'change24h'),
              'average': None,
              'baseVolume': None,
              'quoteVolume': self.safe_number(ticker, 'quoteVolume24h'),
              'info': ticker,
          }
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'market_name': market['id'],
          }
          response = self.publicGetMarketsMarketName(self.extend(request, params))
          #
          #     {
          #         "success":true,
          #         "result":{
          #             "ask":171.29,
          #             "baseCurrency":null,  # base currency for spot markets
          #             "bid":171.24,
          #             "change1h":-0.0012244897959183673,
          #             "change24h":-0.031603346901854366,
          #             "changeBod":-0.03297013492914808,
          #             "enabled":true,
          #             "last":171.44,
          #             "name":"ETH-PERP",
          #             "price":171.29,
          #             "priceIncrement":0.01,
          #             "quoteCurrency":null,  # quote currency for spot markets
          #             "quoteVolume24h":8570651.12113,
          #             "sizeIncrement":0.001,
          #             "type":"future",
          #             "underlying":"ETH",  # null for spot markets
          #             "volumeUsd24h":8570651.12113,
          #         }
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.parse_ticker(result, market)
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          response = self.publicGetMarkets(params)
          #
          #     {
          #         'success': True,
          #         "result": [
          #             {
          #                 "ask":170.44,
          #                 "baseCurrency":"ETH",
          #                 "bid":170.41,
          #                 "change1h":-0.018485459257126403,
          #                 "change24h":-0.023825887743413515,
          #                 "changeBod":-0.037605872388481086,
          #                 "enabled":true,
          #                 "last":172.72,
          #                 "name":"ETH/USD",
          #                 "price":170.44,
          #                 "priceIncrement":0.01,
          #                 "quoteCurrency":"USD",
          #                 "quoteVolume24h":382802.0252,
          #                 "sizeIncrement":0.001,
          #                 "type":"spot",
          #                 "underlying":null,
          #                 "volumeUsd24h":382802.0252
          #             },
          #         ],
          #     }
          #
          tickers = self.safe_value(response, 'result', [])
          return self.parse_tickers(tickers, symbols)
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'market_name': market['id'],
          }
          if limit is not None:
              request['depth'] = limit  # max 100, default 20
          response = self.publicGetMarketsMarketNameOrderbook(self.extend(request, params))
          #
          #     {
          #         "success":true,
          #         "result":{
          #             "asks":[
          #                 [171.95,279.865],
          #                 [171.98,102.42],
          #                 [171.99,124.11],
          #             ],
          #             "bids":[
          #                 [171.93,69.749],
          #                 [171.9,288.325],
          #                 [171.88,87.47],
          #             ],
          #         }
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.parse_order_book(result, symbol)
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          #     {
          #         "close":177.23,
          #         "high":177.45,
          #         "low":177.2,
          #         "open":177.43,
          #         "startTime":"2019-10-17T13:27:00+00:00",
          #         "time":1571318820000.0,
          #         "volume":0.0
          #     }
          #
          return [
              self.safe_integer(ohlcv, 'time'),
              self.safe_number(ohlcv, 'open'),
              self.safe_number(ohlcv, 'high'),
              self.safe_number(ohlcv, 'low'),
              self.safe_number(ohlcv, 'close'),
              self.safe_number(ohlcv, 'volume'),
          ]
  
      def get_market_id(self, symbol, key, params={}):
          parts = self.get_market_params(symbol, key, params)
          return self.safe_string(parts, 1, symbol)
  
      def get_market_params(self, symbol, key, params={}):
          market = None
          marketId = None
          if symbol in self.markets:
              market = self.market(symbol)
              marketId = market['id']
          else:
              marketId = self.safe_string(params, key, symbol)
          return [market, marketId]
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          market, marketId = self.get_market_params(symbol, 'market_name', params)
          request = {
              'resolution': self.timeframes[timeframe],
              'market_name': marketId,
          }
          # max 1501 candles, including the current candle when since is not specified
          limit = 1501 if (limit is None) else limit
          if since is None:
              request['end_time'] = self.seconds()
              request['limit'] = limit
              request['start_time'] = request['end_time'] - limit * self.parse_timeframe(timeframe)
          else:
              request['start_time'] = int(since / 1000)
              request['limit'] = limit
              request['end_time'] = self.sum(request['start_time'], limit * self.parse_timeframe(timeframe))
          response = self.publicGetMarketsMarketNameCandles(self.extend(request, params))
          #
          #     {
          #         "success": True,
          #         "result":[
          #             {
          #                 "close":177.23,
          #                 "high":177.45,
          #                 "low":177.2,
          #                 "open":177.43,
          #                 "startTime":"2019-10-17T13:27:00+00:00",
          #                 "time":1571318820000.0,
          #                 "volume":0.0
          #             },
          #             {
          #                 "close":177.26,
          #                 "high":177.33,
          #                 "low":177.23,
          #                 "open":177.23,
          #                 "startTime":"2019-10-17T13:28:00+00:00",
          #                 "time":1571318880000.0,
          #                 "volume":0.0
          #             },
          #         ],
          #     }
          #
          result = self.safe_value(response, 'result', [])
          return self.parse_ohlcvs(result, market, timeframe, since, limit)
  
      def parse_trade(self, trade, market=None):
          #
          # fetchTrades(public)
          #
          #     {
          #         "id":1715826,
          #         "liquidation":false,
          #         "price":171.62,
          #         "side":"buy",
          #         "size":2.095,
          #         "time":"2019-10-18T12:59:54.288166+00:00"
          #     }
          #
          # fetchMyTrades(private)
          #
          #     {
          #         "fee": 20.1374935,
          #         "feeRate": 0.0005,
          #         "feeCurrency": "USD",
          #         "future": "EOS-0329",
          #         "id": 11215,
          #         "liquidity": "taker",
          #         "market": "EOS-0329",
          #         "baseCurrency": null,
          #         "quoteCurrency": null,
          #         "orderId": 8436981,
          #         "price": 4.201,
          #         "side": "buy",
          #         "size": 9587,
          #         "time": "2019-03-27T19:15:10.204619+00:00",
          #         "type": "order"
          #     }
          #
          #     {
          #         "baseCurrency": "BTC",
          #         "fee": 0,
          #         "feeCurrency": "USD",
          #         "feeRate": 0,
          #         "future": null,
          #         "id": 664079556,
          #         "liquidity": "taker",
          #         "market": null,
          #         "orderId": null,
          #         "price": 34830.61359,
          #         "quoteCurrency": "USD",
          #         "side": "sell",
          #         "size": 0.0005996,
          #         "time": "2021-01-15T16:05:29.246135+00:00",
          #         "tradeId": null,
          #         "type": "otc"
          #     }
          #
          #     with -ve fee
          #     {
          #         "id": 1171258927,
          #         "fee": -0.0000713875,
          #         "side": "sell",
          #         "size": 1,
          #         "time": "2021-03-11T13:34:35.523627+00:00",
          #         "type": "order",
          #         "price": 14.2775,
          #         "future": null,
          #         "market": "SOL/USD",
          #         "feeRate": -0.000005,
          #         "orderId": 33182929044,
          #         "tradeId": 582936801,
          #         "liquidity": "maker",
          #         "feeCurrency": "USD",
          #         "baseCurrency": "SOL",
          #         "quoteCurrency": "USD"
          #     }
          #
          #     # from OTC order
          #     {
          #         "id": 1172129651,
          #         "fee": 0,
          #         "side": "sell",
          #         "size": 1.47568846,
          #         "time": "2021-03-11T15:04:46.893383+00:00",
          #         "type": "otc",
          #         "price": 14.60932598,
          #         "future": null,
          #         "market": null,
          #         "feeRate": 0,
          #         "orderId": null,
          #         "tradeId": null,
          #         "liquidity": "taker",
          #         "feeCurrency": "USD",
          #         "baseCurrency": "BCHA",
          #         "quoteCurrency": "USD"
          #     }
          id = self.safe_string(trade, 'id')
          takerOrMaker = self.safe_string(trade, 'liquidity')
          marketId = self.safe_string(trade, 'market')
          symbol = None
          if marketId in self.markets_by_id:
              market = self.markets_by_id[marketId]
              symbol = market['symbol']
          else:
              base = self.safe_currency_code(self.safe_string(trade, 'baseCurrency'))
              quote = self.safe_currency_code(self.safe_string(trade, 'quoteCurrency'))
              if (base is not None) and (quote is not None):
                  symbol = base + '/' + quote
              else:
                  symbol = marketId
          timestamp = self.parse8601(self.safe_string(trade, 'time'))
          priceString = self.safe_string(trade, 'price')
          amountString = self.safe_string(trade, 'size')
          price = self.parse_number(priceString)
          amount = self.parse_number(amountString)
          cost = self.parse_number(Precise.string_mul(priceString, amountString))
          if (symbol is None) and (market is not None):
              symbol = market['symbol']
          side = self.safe_string(trade, 'side')
          fee = None
          feeCost = self.safe_number(trade, 'fee')
          if feeCost is not None:
              feeCurrencyId = self.safe_string(trade, 'feeCurrency')
              feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
              fee = {
                  'cost': feeCost,
                  'currency': feeCurrencyCode,
                  'rate': self.safe_number(trade, 'feeRate'),
              }
          orderId = self.safe_string(trade, 'orderId')
          return {
              'info': trade,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'id': id,
              'order': orderId,
              'type': None,
              'takerOrMaker': takerOrMaker,
              'side': side,
              'price': price,
              'amount': amount,
              'cost': cost,
              'fee': fee,
          }
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market, marketId = self.get_market_params(symbol, 'market_name', params)
          request = {
              'market_name': marketId,
          }
          if since is not None:
              request['start_time'] = int(since / 1000)
              # start_time doesn't work without end_time
              request['end_time'] = self.seconds()
          if limit is not None:
              request['limit'] = limit
          response = self.publicGetMarketsMarketNameTrades(self.extend(request, params))
          #
          #     {
          #         "success":true,
          #         "result":[
          #             {
          #                 "id":1715826,
          #                 "liquidation":false,
          #                 "price":171.62,
          #                 "side":"buy",
          #                 "size":2.095,
          #                 "time":"2019-10-18T12:59:54.288166+00:00"
          #             },
          #             {
          #                 "id":1715763,
          #                 "liquidation":false,
          #                 "price":171.89,
          #                 "side":"sell",
          #                 "size":1.477,
          #                 "time":"2019-10-18T12:58:38.443734+00:00"
          #             },
          #         ],
          #     }
          #
          result = self.safe_value(response, 'result', [])
          return self.parse_trades(result, market, since, limit)
  
      def fetch_trading_fees(self, params={}):
          self.load_markets()
          response = self.privateGetAccount(params)
          #
          #     {
          #         "success": True,
          #         "result": {
          #             "backstopProvider": True,
          #             "collateral": 3568181.02691129,
          #             "freeCollateral": 1786071.456884368,
          #             "initialMarginRequirement": 0.12222384240257728,
          #             "liquidating": False,
          #             "maintenanceMarginRequirement": 0.07177992558058484,
          #             "makerFee": 0.0002,
          #             "marginFraction": 0.5588433331419503,
          #             "openMarginFraction": 0.2447194090423075,
          #             "takerFee": 0.0005,
          #             "totalAccountValue": 3568180.98341129,
          #             "totalPositionSize": 6384939.6992,
          #             "username": "user@domain.com",
          #             "positions": [
          #                 {
          #                     "cost": -31.7906,
          #                     "entryPrice": 138.22,
          #                     "future": "ETH-PERP",
          #                     "initialMarginRequirement": 0.1,
          #                     "longOrderSize": 1744.55,
          #                     "maintenanceMarginRequirement": 0.04,
          #                     "netSize": -0.23,
          #                     "openSize": 1744.32,
          #                     "realizedPnl": 3.39441714,
          #                     "shortOrderSize": 1732.09,
          #                     "side": "sell",
          #                     "size": 0.23,
          #                     "unrealizedPnl": 0,
          #                 },
          #             ],
          #         },
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return {
              'info': response,
              'maker': self.safe_number(result, 'makerFee'),
              'taker': self.safe_number(result, 'takerFee'),
          }
  
      def fetch_balance(self, params={}):
          self.load_markets()
          response = self.privateGetWalletBalances(params)
          #
          #     {
          #         "success": True,
          #         "result": [
          #             {
          #                 "coin": "USDTBEAR",
          #                 "free": 2320.2,
          #                 "total": 2340.2
          #             },
          #         ],
          #     }
          #
          result = {
              'info': response,
          }
          balances = self.safe_value(response, 'result', [])
          for i in range(0, len(balances)):
              balance = balances[i]
              code = self.safe_currency_code(self.safe_string(balance, 'coin'))
              account = self.account()
              account['free'] = self.safe_string(balance, 'free')
              account['total'] = self.safe_string(balance, 'total')
              result[code] = account
          return self.parse_balance(result, False)
  
      def parse_order_status(self, status):
          statuses = {
              'new': 'open',
              'open': 'open',
              'closed': 'closed',  # filled or canceled
              'triggered': 'closed',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_order(self, order, market=None):
          #
          # limit orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder, editOrder
          #
          #     {
          #         "createdAt": "2019-03-05T09:56:55.728933+00:00",
          #         "filledSize": 0,
          #         "future": "XRP-PERP",
          #         "id": 9596912,
          #         "market": "XRP-PERP",
          #         "price": 0.306525,
          #         "remainingSize": 31431,
          #         "side": "sell",
          #         "size": 31431,
          #         "status": "open",
          #         "type": "limit",
          #         "reduceOnly": False,
          #         "ioc": False,
          #         "postOnly": False,
          #         "clientId": null,
          #     }
          #
          # market orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder
          #
          #     {
          #         "avgFillPrice": 2666.0,
          #         "clientId": None,
          #         "createdAt": "2020-02-12T00: 53: 49.009726+00: 00",
          #         "filledSize": 0.0007,
          #         "future": None,
          #         "id": 3109208514,
          #         "ioc": True,
          #         "market": "BNBBULL/USD",
          #         "postOnly": False,
          #         "price": None,
          #         "reduceOnly": False,
          #         "remainingSize": 0.0,
          #         "side": "buy",
          #         "size": 0.0007,
          #         "status": "closed",
          #         "type": "market"
          #     }
          #
          # createOrder(conditional, "stop", "trailingStop", or "takeProfit")
          #
          #     {
          #         "createdAt": "2019-03-05T09:56:55.728933+00:00",
          #         "future": "XRP-PERP",
          #         "id": 9596912,
          #         "market": "XRP-PERP",
          #         "triggerPrice": 0.306525,
          #         "orderId": null,
          #         "side": "sell",
          #         "size": 31431,
          #         "status": "open",
          #         "type": "stop",
          #         "orderPrice": null,
          #         "error": null,
          #         "triggeredAt": null,
          #         "reduceOnly": False
          #     }
          #
          # editOrder(conditional, stop, trailing stop, take profit)
          #
          #     {
          #         "createdAt": "2019-03-05T09:56:55.728933+00:00",
          #         "future": "XRP-PERP",
          #         "id": 9596912,
          #         "market": "XRP-PERP",
          #         "triggerPrice": 0.306225,
          #         "orderId": null,
          #         "side": "sell",
          #         "size": 31431,
          #         "status": "open",
          #         "type": "stop",
          #         "orderPrice": null,
          #         "error": null,
          #         "triggeredAt": null,
          #         "reduceOnly": False,
          #         "orderType": "market",
          #         "filledSize": 0,
          #         "avgFillPrice": null,
          #         "retryUntilFilled": False
          #     }
          #
          # canceled order with a closed status
          #
          #     {
          #         "avgFillPrice":null,
          #         "clientId":null,
          #         "createdAt":"2020-09-01T13:45:57.119695+00:00",
          #         "filledSize":0.0,
          #         "future":null,
          #         "id":8553541288,
          #         "ioc":false,
          #         "liquidation":false,
          #         "market":"XRP/USDT",
          #         "postOnly":false,
          #         "price":0.5,
          #         "reduceOnly":false,
          #         "remainingSize":0.0,
          #         "side":"sell",
          #         "size":46.0,
          #         "status":"closed",
          #         "type":"limit"
          #     }
          #
          id = self.safe_string(order, 'id')
          timestamp = self.parse8601(self.safe_string(order, 'createdAt'))
          status = self.parse_order_status(self.safe_string(order, 'status'))
          amount = self.safe_number(order, 'size')
          filled = self.safe_number(order, 'filledSize')
          remaining = self.safe_number(order, 'remainingSize')
          if (remaining == 0.0) and (amount is not None) and (filled is not None):
              remaining = max(amount - filled, 0)
              if remaining > 0:
                  status = 'canceled'
          symbol = None
          marketId = self.safe_string(order, 'market')
          if marketId is not None:
              if marketId in self.markets_by_id:
                  market = self.markets_by_id[marketId]
                  symbol = market['symbol']
              else:
                  # support for delisted market ids
                  # https://github.com/ccxt/ccxt/issues/7113
                  symbol = marketId
          if (symbol is None) and (market is not None):
              symbol = market['symbol']
          side = self.safe_string(order, 'side')
          type = self.safe_string(order, 'type')
          average = self.safe_number(order, 'avgFillPrice')
          price = self.safe_number_2(order, 'price', 'triggerPrice', average)
          cost = None
          if filled is not None and price is not None:
              cost = filled * price
          lastTradeTimestamp = self.parse8601(self.safe_string(order, 'triggeredAt'))
          clientOrderId = self.safe_string(order, 'clientId')
          stopPrice = self.safe_number(order, 'triggerPrice')
          postOnly = self.safe_value(order, 'postOnly')
          return {
              'info': order,
              'id': id,
              'clientOrderId': clientOrderId,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': lastTradeTimestamp,
              'symbol': symbol,
              'type': type,
              'timeInForce': None,
              'postOnly': postOnly,
              'side': side,
              'price': price,
              'stopPrice': stopPrice,
              'amount': amount,
              'cost': cost,
              'average': average,
              'filled': filled,
              'remaining': remaining,
              'status': status,
              'fee': None,
              'trades': None,
          }
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'market': market['id'],
              'side': side,  # "buy" or "sell"
              # 'price': 0.306525,  # send null for market orders
              'type': type,  # "limit", "market", "stop", "trailingStop", or "takeProfit"
              'size': float(self.amount_to_precision(symbol, amount)),
              # 'reduceOnly': False,  # optional, default is False
              # 'ioc': False,  # optional, default is False, limit or market orders only
              # 'postOnly': False,  # optional, default is False, limit or market orders only
              # 'clientId': 'abcdef0123456789',  # string, optional, client order id, limit or market orders only
          }
          clientOrderId = self.safe_string_2(params, 'clientId', 'clientOrderId')
          if clientOrderId is not None:
              request['clientId'] = clientOrderId
              params = self.omit(params, ['clientId', 'clientOrderId'])
          method = None
          if type == 'limit':
              method = 'privatePostOrders'
              request['price'] = float(self.price_to_precision(symbol, price))
          elif type == 'market':
              method = 'privatePostOrders'
              request['price'] = None
          elif (type == 'stop') or (type == 'takeProfit'):
              method = 'privatePostConditionalOrders'
              stopPrice = self.safe_number_2(params, 'stopPrice', 'triggerPrice')
              if stopPrice is None:
                  raise ArgumentsRequired(self.id + ' createOrder() requires a stopPrice parameter or a triggerPrice parameter for ' + type + ' orders')
              else:
                  params = self.omit(params, ['stopPrice', 'triggerPrice'])
                  request['triggerPrice'] = float(self.price_to_precision(symbol, stopPrice))
              if price is not None:
                  request['orderPrice'] = float(self.price_to_precision(symbol, price))  # optional, order type is limit if self is specified, otherwise market
          elif type == 'trailingStop':
              method = 'privatePostConditionalOrders'
              request['trailValue'] = float(self.price_to_precision(symbol, price))  # negative for "sell", positive for "buy"
          else:
              raise InvalidOrder(self.id + ' createOrder() does not support order type ' + type + ', only limit, market, stop, trailingStop, or takeProfit orders are supported')
          response = getattr(self, method)(self.extend(request, params))
          #
          # orders
          #
          #     {
          #         "success": True,
          #         "result": [
          #             {
          #                 "createdAt": "2019-03-05T09:56:55.728933+00:00",
          #                 "filledSize": 0,
          #                 "future": "XRP-PERP",
          #                 "id": 9596912,
          #                 "market": "XRP-PERP",
          #                 "price": 0.306525,
          #                 "remainingSize": 31431,
          #                 "side": "sell",
          #                 "size": 31431,
          #                 "status": "open",
          #                 "type": "limit",
          #                 "reduceOnly": False,
          #                 "ioc": False,
          #                 "postOnly": False,
          #                 "clientId": null,
          #             }
          #         ]
          #     }
          #
          # conditional orders
          #
          #     {
          #         "success": True,
          #         "result": [
          #             {
          #                 "createdAt": "2019-03-05T09:56:55.728933+00:00",
          #                 "future": "XRP-PERP",
          #                 "id": 9596912,
          #                 "market": "XRP-PERP",
          #                 "triggerPrice": 0.306525,
          #                 "orderId": null,
          #                 "side": "sell",
          #                 "size": 31431,
          #                 "status": "open",
          #                 "type": "stop",
          #                 "orderPrice": null,
          #                 "error": null,
          #                 "triggeredAt": null,
          #                 "reduceOnly": False
          #             }
          #         ]
          #     }
          #
          #
          result = self.safe_value(response, 'result', [])
          return self.parse_order(result, market)
  
      def edit_order(self, id, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {}
          method = None
          clientOrderId = self.safe_string_2(params, 'client_order_id', 'clientOrderId')
          triggerPrice = self.safe_number(params, 'triggerPrice')
          orderPrice = self.safe_number(params, 'orderPrice')
          trailValue = self.safe_number(params, 'trailValue')
          params = self.omit(params, ['client_order_id', 'clientOrderId', 'triggerPrice', 'orderPrice', 'trailValue'])
          triggerPriceIsDefined = (triggerPrice is not None)
          orderPriceIsDefined = (orderPrice is not None)
          trailValueIsDefined = (trailValue is not None)
          if triggerPriceIsDefined or orderPriceIsDefined or trailValueIsDefined:
              method = 'privatePostConditionalOrdersOrderIdModify'
              request['order_id'] = id
              if triggerPriceIsDefined:
                  request['triggerPrice'] = float(self.price_to_precision(symbol, triggerPrice))
              if orderPriceIsDefined:
                  # only for stop limit or take profit limit orders
                  request['orderPrice'] = float(self.price_to_precision(symbol, orderPrice))
              if trailValueIsDefined:
                  # negative for sell orders, positive for buy orders
                  request['trailValue'] = float(self.price_to_precision(symbol, trailValue))
          else:
              if clientOrderId is None:
                  method = 'privatePostOrdersOrderIdModify'
                  request['order_id'] = id
              else:
                  method = 'privatePostOrdersByClientIdClientOrderIdModify'
                  request['client_order_id'] = clientOrderId
                  # request['clientId'] = clientOrderId
              if price is not None:
                  request['price'] = float(self.price_to_precision(symbol, price))
          if amount is not None:
              request['size'] = float(self.amount_to_precision(symbol, amount))
          response = getattr(self, method)(self.extend(request, params))
          #
          # regular order
          #
          #     {
          #         "success": True,
          #         "result": {
          #             "createdAt": "2019-03-05T11:56:55.728933+00:00",
          #             "filledSize": 0,
          #             "future": "XRP-PERP",
          #             "id": 9596932,
          #             "market": "XRP-PERP",
          #             "price": 0.326525,
          #             "remainingSize": 31431,
          #             "side": "sell",
          #             "size": 31431,
          #             "status": "open",
          #             "type": "limit",
          #             "reduceOnly": False,
          #             "ioc": False,
          #             "postOnly": False,
          #             "clientId": null,
          #         }
          #     }
          #
          # conditional trigger order
          #
          #     {
          #         "success": True,
          #         "result": {
          #             "createdAt": "2019-03-05T09:56:55.728933+00:00",
          #             "future": "XRP-PERP",
          #             "id": 9596912,
          #             "market": "XRP-PERP",
          #             "triggerPrice": 0.306225,
          #             "orderId": null,
          #             "side": "sell",
          #             "size": 31431,
          #             "status": "open",
          #             "type": "stop",
          #             "orderPrice": null,
          #             "error": null,
          #             "triggeredAt": null,
          #             "reduceOnly": False,
          #             "orderType": "market",
          #             "filledSize": 0,
          #             "avgFillPrice": null,
          #             "retryUntilFilled": False
          #         }
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.parse_order(result, market)
  
      def cancel_order(self, id, symbol=None, params={}):
          self.load_markets()
          request = {}
          # support for canceling conditional orders
          # https://github.com/ccxt/ccxt/issues/6669
          options = self.safe_value(self.options, 'cancelOrder', {})
          defaultMethod = self.safe_string(options, 'method', 'privateDeleteOrdersOrderId')
          method = self.safe_string(params, 'method', defaultMethod)
          type = self.safe_value(params, 'type')
          clientOrderId = self.safe_value_2(params, 'client_order_id', 'clientOrderId')
          if clientOrderId is None:
              request['order_id'] = int(id)
              if (type == 'stop') or (type == 'trailingStop') or (type == 'takeProfit'):
                  method = 'privateDeleteConditionalOrdersOrderId'
          else:
              request['client_order_id'] = clientOrderId
              method = 'privateDeleteOrdersByClientIdClientOrderId'
          query = self.omit(params, ['method', 'type', 'client_order_id', 'clientOrderId'])
          response = getattr(self, method)(self.extend(request, query))
          #
          #     {
          #         "success": True,
          #         "result": "Order queued for cancelation"
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return result
  
      def cancel_all_orders(self, symbol=None, params={}):
          self.load_markets()
          request = {
              # 'market': market['id'],  # optional
              # 'conditionalOrdersOnly': False,  # cancel conditional orders only
              # 'limitOrdersOnly': False,  # cancel existing limit orders(non-conditional orders) only
          }
          marketId = self.get_market_id(symbol, 'market', params)
          if marketId is not None:
              request['market'] = marketId
          response = self.privateDeleteOrders(self.extend(request, params))
          result = self.safe_value(response, 'result', {})
          #
          #     {
          #         "success": True,
          #         "result": "Orders queued for cancelation"
          #     }
          #
          return result
  
      def fetch_order(self, id, symbol=None, params={}):
          self.load_markets()
          request = {}
          clientOrderId = self.safe_value_2(params, 'client_order_id', 'clientOrderId')
          method = 'privateGetOrdersOrderId'
          if clientOrderId is None:
              request['order_id'] = id
          else:
              request['client_order_id'] = clientOrderId
              params = self.omit(params, ['client_order_id', 'clientOrderId'])
              method = 'privateGetOrdersByClientIdClientOrderId'
          response = getattr(self, method)(self.extend(request, params))
          #
          #     {
          #         "success": True,
          #         "result": {
          #             "createdAt": "2019-03-05T09:56:55.728933+00:00",
          #             "filledSize": 10,
          #             "future": "XRP-PERP",
          #             "id": 9596912,
          #             "market": "XRP-PERP",
          #             "price": 0.306525,
          #             "avgFillPrice": 0.306526,
          #             "remainingSize": 31421,
          #             "side": "sell",
          #             "size": 31431,
          #             "status": "open",
          #             "type": "limit",
          #             "reduceOnly": False,
          #             "ioc": False,
          #             "postOnly": False,
          #             "clientId": null
          #         }
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.parse_order(result)
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          market, marketId = self.get_market_params(symbol, 'market', params)
          if marketId is not None:
              request['market'] = marketId
          # support for canceling conditional orders
          # https://github.com/ccxt/ccxt/issues/6669
          options = self.safe_value(self.options, 'fetchOpenOrders', {})
          defaultMethod = self.safe_string(options, 'method', 'privateGetOrders')
          method = self.safe_string(params, 'method', defaultMethod)
          type = self.safe_value(params, 'type')
          if (type == 'stop') or (type == 'trailingStop') or (type == 'takeProfit'):
              method = 'privateGetConditionalOrders'
          query = self.omit(params, ['method', 'type'])
          response = getattr(self, method)(self.extend(request, query))
          #
          #     {
          #         "success": True,
          #         "result": [
          #             {
          #                 "createdAt": "2019-03-05T09:56:55.728933+00:00",
          #                 "filledSize": 10,
          #                 "future": "XRP-PERP",
          #                 "id": 9596912,
          #                 "market": "XRP-PERP",
          #                 "price": 0.306525,
          #                 "avgFillPrice": 0.306526,
          #                 "remainingSize": 31421,
          #                 "side": "sell",
          #                 "size": 31431,
          #                 "status": "open",
          #                 "type": "limit",
          #                 "reduceOnly": False,
          #                 "ioc": False,
          #                 "postOnly": False,
          #                 "clientId": null
          #             }
          #         ]
          #     }
          #
          result = self.safe_value(response, 'result', [])
          return self.parse_orders(result, market, since, limit)
  
      def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          market, marketId = self.get_market_params(symbol, 'market', params)
          if marketId is not None:
              request['market'] = marketId
          if limit is not None:
              request['limit'] = limit  # default 100, max 100
          if since is not None:
              request['start_time'] = int(since / 1000)
          # support for canceling conditional orders
          # https://github.com/ccxt/ccxt/issues/6669
          options = self.safe_value(self.options, 'fetchOrders', {})
          defaultMethod = self.safe_string(options, 'method', 'privateGetOrdersHistory')
          method = self.safe_string(params, 'method', defaultMethod)
          type = self.safe_value(params, 'type')
          if (type == 'stop') or (type == 'trailingStop') or (type == 'takeProfit'):
              method = 'privateGetConditionalOrdersHistory'
          query = self.omit(params, ['method', 'type'])
          response = getattr(self, method)(self.extend(request, query))
          #
          #     {
          #         "success": True,
          #         "result": [
          #             {
          #                 "createdAt": "2019-03-05T09:56:55.728933+00:00",
          #                 "filledSize": 10,
          #                 "future": "XRP-PERP",
          #                 "id": 9596912,
          #                 "market": "XRP-PERP",
          #                 "price": 0.306525,
          #                 "avgFillPrice": 0.306526,
          #                 "remainingSize": 31421,
          #                 "side": "sell",
          #                 "size": 31431,
          #                 "status": "open",
          #                 "type": "limit",
          #                 "reduceOnly": False,
          #                 "ioc": False,
          #                 "postOnly": False,
          #                 "clientId": null
          #             }
          #         ]
          #     }
          #
          result = self.safe_value(response, 'result', [])
          return self.parse_orders(result, market, since, limit)
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          market, marketId = self.get_market_params(symbol, 'market', params)
          request = {}
          if marketId is not None:
              request['market'] = marketId
          if limit is not None:
              request['limit'] = limit
          if since is not None:
              request['start_time'] = int(since / 1000)
              request['end_time'] = self.seconds()
          response = self.privateGetFills(self.extend(request, params))
          #
          #     {
          #         "success": True,
          #         "result": [
          #             {
          #                 "fee": 20.1374935,
          #                 "feeRate": 0.0005,
          #                 "future": "EOS-0329",
          #                 "id": 11215,
          #                 "liquidity": "taker",
          #                 "market": "EOS-0329",
          #                 "baseCurrency": null,
          #                 "quoteCurrency": null,
          #                 "orderId": 8436981,
          #                 "price": 4.201,
          #                 "side": "buy",
          #                 "size": 9587,
          #                 "time": "2019-03-27T19:15:10.204619+00:00",
          #                 "type": "order"
          #             }
          #         ]
          #     }
          #
          trades = self.safe_value(response, 'result', [])
          return self.parse_trades(trades, market, since, limit)
  
      def withdraw(self, code, amount, address, tag=None, params={}):
          self.load_markets()
          self.check_address(address)
          currency = self.currency(code)
          request = {
              'coin': currency['id'],
              'size': amount,
              'address': address,
              # 'password': 'string',  # optional withdrawal password if it is required for your account
              # 'code': '192837',  # optional 2fa code if it is required for your account
          }
          if self.password is not None:
              request['password'] = self.password
          if tag is not None:
              request['tag'] = tag
          response = self.privatePostWalletWithdrawals(self.extend(request, params))
          #
          #     {
          #         "success": True,
          #         "result": {
          #             "coin": "USDTBEAR",
          #             "address": "0x83a127952d266A6eA306c40Ac62A4a70668FE3BE",
          #             "tag": "null",
          #             "fee": 0,
          #             "id": 1,
          #             "size": "20.2",
          #             "status": "requested",
          #             "time": "2019-03-05T09:56:55.728933+00:00",
          #             "txid": "null"
          #         }
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.parse_transaction(result, currency)
  
      def fetch_positions(self, symbols=None, params={}):
          self.load_markets()
          response = self.privateGetAccount(params)
          #
          #     {
          #         "result":{
          #             "backstopProvider":false,
          #             "chargeInterestOnNegativeUsd":false,
          #             "collateral":2830.2567913677476,
          #             "freeCollateral":2829.670741867416,
          #             "initialMarginRequirement":0.05,
          #             "leverage":20.0,
          #             "liquidating":false,
          #             "maintenanceMarginRequirement":0.03,
          #             "makerFee":0.0,
          #             "marginFraction":null,
          #             "openMarginFraction":null,
          #             "positionLimit":null,
          #             "positionLimitUsed":null,
          #             "positions":[
          #                 {
          #                     "collateralUsed":0.0,
          #                     "cost":0.0,
          #                     "entryPrice":null,
          #                     "estimatedLiquidationPrice":null,
          #                     "future":"XRP-PERP",
          #                     "initialMarginRequirement":0.05,
          #                     "longOrderSize":0.0,
          #                     "maintenanceMarginRequirement":0.03,
          #                     "netSize":0.0,
          #                     "openSize":0.0,
          #                     "realizedPnl":0.016,
          #                     "shortOrderSize":0.0,
          #                     "side":"buy",
          #                     "size":0.0,
          #                     "unrealizedPnl":0.0,
          #                 }
          #             ],
          #             "spotLendingEnabled":false,
          #             "spotMarginEnabled":false,
          #             "takerFee":0.0007,
          #             "totalAccountValue":2830.2567913677476,
          #             "totalPositionSize":0.0,
          #             "useFttCollateral":true,
          #             "username":"igor.kroitor@gmail.com"
          #         },
          #         "success":true
          #     }
          #
          result = self.safe_value(response, 'result', {})
          # todo unify parsePosition/parsePositions
          return self.safe_value(result, 'positions', [])
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'coin': currency['id'],
          }
          response = self.privateGetWalletDepositAddressCoin(self.extend(request, params))
          #
          #     {
          #         "success": True,
          #         "result": {
          #             "address": "0x83a127952d266A6eA306c40Ac62A4a70668FE3BE",
          #             "tag": "null"
          #         }
          #     }
          #
          result = self.safe_value(response, 'result', {})
          address = self.safe_string(result, 'address')
          tag = self.safe_string(result, 'tag')
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'tag': tag,
              'info': response,
          }
  
      def parse_transaction_status(self, status):
          statuses = {
              # what are other statuses here?
              'confirmed': 'ok',  # deposits
              'complete': 'ok',  # withdrawals
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchDeposits
          #
          #     airdrop
          #
          #     {
          #         "id": 9147072,
          #         "coin": "SRM_LOCKED",
          #         "size": 3.12,
          #         "time": "2021-04-27T23:59:03.565983+00:00",
          #         "notes": "SRM Airdrop for FTT holdings",
          #         "status": "complete"
          #     }
          #
          #     regular deposits
          #
          #     {
          #         "coin": "TUSD",
          #         "confirmations": 64,
          #         "confirmedTime": "2019-03-05T09:56:55.728933+00:00",
          #         "fee": 0,
          #         "id": 1,
          #         "sentTime": "2019-03-05T09:56:55.735929+00:00",
          #         "size": "99.0",
          #         "status": "confirmed",
          #         "time": "2019-03-05T09:56:55.728933+00:00",
          #         "txid": "0x8078356ae4b06a036d64747546c274af19581f1c78c510b60505798a7ffcaf1"
          #     }
          #
          # fetchWithdrawals
          #
          #     {
          #         "coin": "TUSD",
          #         "address": "0x83a127952d266A6eA306c40Ac62A4a70668FE3BE",
          #         "tag": "null",
          #         "fee": 0,
          #         "id": 1,
          #         "size": "99.0",
          #         "status": "complete",
          #         "time": "2019-03-05T09:56:55.728933+00:00",
          #         "txid": "0x8078356ae4b06a036d64747546c274af19581f1c78c510b60505798a7ffcaf1"
          #     }
          #
          #     {
          #         "coin": 'BTC',
          #         "id": 1969806,
          #         "notes": 'Transfer to Dd6gi7m2Eg4zzBbPAxuwfEaHs6tYvyUX5hbPpsTcNPXo',
          #         "size": 0.003,
          #         "status": 'complete',
          #         "time": '2021-02-03T20:28:54.918146+00:00'
          #     }
          #
          code = self.safe_currency_code(self.safe_string(transaction, 'coin'))
          id = self.safe_string(transaction, 'id')
          amount = self.safe_number(transaction, 'size')
          status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
          timestamp = self.parse8601(self.safe_string(transaction, 'time'))
          txid = self.safe_string(transaction, 'txid')
          tag = None
          address = self.safe_value(transaction, 'address')
          if not isinstance(address, basestring):
              tag = self.safe_string(address, 'tag')
              address = self.safe_string(address, 'address')
          if address is None:
              # parse address from internal transfer
              notes = self.safe_string(transaction, 'notes')
              if (notes is not None) and (notes.find('Transfer to') >= 0):
                  address = notes[12:]
          fee = self.safe_number(transaction, 'fee')
          return {
              'info': transaction,
              'id': id,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'addressFrom': None,
              'address': address,
              'addressTo': address,
              'tagFrom': None,
              'tag': tag,
              'tagTo': tag,
              'type': None,
              'amount': amount,
              'currency': code,
              'status': status,
              'updated': None,
              'fee': {
                  'currency': code,
                  'cost': fee,
                  'rate': None,
              },
          }
  
      def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          response = self.privateGetWalletDeposits(params)
          #
          #     {
          #         "success": True,
          #         "result": {
          #             "coin": "TUSD",
          #             "confirmations": 64,
          #             "confirmedTime": "2019-03-05T09:56:55.728933+00:00",
          #             "fee": 0,
          #             "id": 1,
          #             "sentTime": "2019-03-05T09:56:55.735929+00:00",
          #             "size": "99.0",
          #             "status": "confirmed",
          #             "time": "2019-03-05T09:56:55.728933+00:00",
          #             "txid": "0x8078356ae4b06a036d64747546c274af19581f1c78c510b60505798a7ffcaf1"
          #         }
          #     }
          #
          result = self.safe_value(response, 'result', [])
          currency = None
          if code is not None:
              currency = self.currency(code)
          return self.parse_transactions(result, currency, since, limit, {'type': 'deposit'})
  
      def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          response = self.privateGetWalletWithdrawals(params)
          #
          #     {
          #         "success": True,
          #         "result": {
          #             "coin": "TUSD",
          #             "address": "0x83a127952d266A6eA306c40Ac62A4a70668FE3BE",
          #             "tag": "null",
          #             "fee": 0,
          #             "id": 1,
          #             "size": "99.0",
          #             "status": "complete",
          #             "time": "2019-03-05T09:56:55.728933+00:00",
          #             "txid": "0x8078356ae4b06a036d64747546c274af19581f1c78c510b60505798a7ffcaf1"
          #         }
          #     }
          #
          result = self.safe_value(response, 'result', [])
          currency = None
          if code is not None:
              currency = self.currency(code)
          return self.parse_transactions(result, currency, since, limit, {'type': 'withdrawal'})
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          request = '/api/' + self.implode_params(path, params)
          query = self.omit(params, self.extract_params(path))
          baseUrl = self.implode_params(self.urls['api'][api], {'hostname': self.hostname})
          url = baseUrl + request
          if method != 'POST':
              if query:
                  suffix = '?' + self.urlencode(query)
                  url += suffix
                  request += suffix
          if api == 'private':
              self.check_required_credentials()
              timestamp = str(self.milliseconds())
              auth = timestamp + method + request
              headers = {}
              if (method == 'POST') or (method == 'DELETE'):
                  body = self.json(query)
                  auth += body
                  headers['Content-Type'] = 'application/json'
              signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
              options = self.safe_value(self.options, 'sign', {})
              headerPrefix = self.safe_string(options, self.hostname, 'FTX')
              keyField = headerPrefix + '-KEY'
              tsField = headerPrefix + '-TS'
              signField = headerPrefix + '-SIGN'
              headers[keyField] = self.apiKey
              headers[tsField] = timestamp
              headers[signField] = signature
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if response is None:
              return  # fallback to the default error handler
          #
          #     {"error":"Invalid parameter start_time","success":false}
          #     {"error":"Not enough balances","success":false}
          #
          success = self.safe_value(response, 'success')
          if not success:
              feedback = self.id + ' ' + body
              error = self.safe_string(response, 'error')
              self.throw_exactly_matched_exception(self.exceptions['exact'], error, feedback)
              self.throw_broadly_matched_exception(self.exceptions['broad'], error, feedback)
              raise ExchangeError(feedback)  # unknown message
  