text: # -*- coding: utf-8 -*-
  
  # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
  
  from ccxt.base.exchange import Exchange
  import math
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  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 ExchangeNotAvailable
  from ccxt.base.decimal_to_precision import TICK_SIZE
  from ccxt.base.precise import Precise
  
  
  class delta(Exchange):
  
      def describe(self):
          return self.deep_extend(super(delta, self).describe(), {
              'id': 'delta',
              'name': 'Delta Exchange',
              'countries': ['VC'],  # Saint Vincent and the Grenadines
              'rateLimit': 300,
              'version': 'v2',
              # new metainfo interface
              'has': {
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'createOrder': True,
                  'editOrder': True,
                  'fetchBalance': True,
                  'fetchClosedOrders': True,
                  'fetchCurrencies': True,
                  'fetchDepositAddress': True,
                  'fetchLedger': True,
                  'fetchMarkets': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrderBook': True,
                  'fetchStatus': True,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTime': True,
                  'fetchTrades': True,
              },
              'timeframes': {
                  '1m': '1m',
                  '3m': '3m',
                  '5m': '5m',
                  '15m': '15m',
                  '30m': '30m',
                  '1h': '1h',
                  '2h': '2h',
                  '4h': '4h',
                  '6h': '6h',
                  '1d': '1d',
                  '7d': '7d',
                  '1w': '1w',
                  '2w': '2w',
                  '1M': '30d',
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/99450025-3be60a00-2931-11eb-9302-f4fd8d8589aa.jpg',
                  'test': {
                      'public': 'https://testnet-api.delta.exchange',
                      'private': 'https://testnet-api.delta.exchange',
                  },
                  'api': {
                      'public': 'https://api.delta.exchange',
                      'private': 'https://api.delta.exchange',
                  },
                  'www': 'https://www.delta.exchange',
                  'doc': [
                      'https://docs.delta.exchange',
                  ],
                  'fees': 'https://www.delta.exchange/fees',
                  'referral': 'https://www.delta.exchange/app/signup/?code=IULYNB',
              },
              'api': {
                  'public': {
                      'get': [
                          'assets',
                          'settings',
                          'indices',
                          'products',
                          'tickers',
                          'tickers/{symbol}',
                          'l2orderbook/{symbol}',
                          'trades/{symbol}',
                          'history/candles',
                          'history/sparklines',
                      ],
                  },
                  'private': {
                      'get': [
                          'orders',
                          'orders/leverage',
                          'positions',
                          'positions/margined',
                          'orders/history',
                          'fills',
                          'fills/history/download/csv',
                          'wallet/balances',
                          'wallet/transactions',
                          'wallet/transactions/download',
                          'deposits/address',
                      ],
                      'post': [
                          'orders',
                          'orders/batch',
                          'orders/leverage',
                          'positions/change_margin',
                      ],
                      'put': [
                          'orders',
                          'orders/batch',
                      ],
                      'delete': [
                          'orders',
                          'orders/all',
                          'orders/batch',
                      ],
                  },
              },
              'fees': {
                  'trading': {
                      'tierBased': True,
                      'percentage': True,
                      'taker': 0.15 / 100,
                      'maker': 0.10 / 100,
                      'tiers': {
                          'taker': [
                              [0, 0.15 / 100],
                              [100, 0.13 / 100],
                              [250, 0.13 / 100],
                              [1000, 0.1 / 100],
                              [5000, 0.09 / 100],
                              [10000, 0.075 / 100],
                              [20000, 0.065 / 100],
                          ],
                          'maker': [
                              [0, 0.1 / 100],
                              [100, 0.1 / 100],
                              [250, 0.09 / 100],
                              [1000, 0.075 / 100],
                              [5000, 0.06 / 100],
                              [10000, 0.05 / 100],
                              [20000, 0.05 / 100],
                          ],
                      },
                  },
              },
              'precisionMode': TICK_SIZE,
              'requiredCredentials': {
                  'apiKey': True,
                  'secret': False,
              },
              'exceptions': {
                  'exact': {
                      # Margin required to place order with selected leverage and quantity is insufficient.
                      'insufficient_margin': InsufficientFunds,  # {"error":{"code":"insufficient_margin","context":{"available_balance":"0.000000000000000000","required_additional_balance":"1.618626000000000000000000000"}},"success":false}
                      'order_size_exceed_available': InvalidOrder,  # The order book doesn't have sufficient liquidity, hence the order couldnt be filled, for example, ioc orders
                      'risk_limits_breached': BadRequest,  # orders couldn't be placed as it will breach allowed risk limits.
                      'invalid_contract': BadSymbol,  # The contract/product is either doesn't exist or has already expired.
                      'immediate_liquidation': InvalidOrder,  # Order will cause immediate liquidation.
                      'out_of_bankruptcy': InvalidOrder,  # Order prices are out of position bankruptcy limits.
                      'self_matching_disrupted_post_only': InvalidOrder,  # Self matching is not allowed during auction.
                      'immediate_execution_post_only': InvalidOrder,  # orders couldn't be placed as it includes post only orders which will be immediately executed
                      'bad_schema': BadRequest,  # {"error":{"code":"bad_schema","context":{"schema_errors":[{"code":"validation_error","message":"id is required","param":""}]}},"success":false}
                      'invalid_api_key': AuthenticationError,  # {"success":false,"error":{"code":"invalid_api_key"}}
                      'invalid_signature': AuthenticationError,  # {"success":false,"error":{"code":"invalid_signature"}}
                      'open_order_not_found': OrderNotFound,  # {"error":{"code":"open_order_not_found"},"success":false}
                      'unavailable': ExchangeNotAvailable,  # {"error":{"code":"unavailable"},"success":false}
                  },
                  'broad': {
                  },
              },
          })
  
      def fetch_time(self, params={}):
          response = self.publicGetSettings(params)
          #
          #     {
          #         "result":{
          #             "server_time":1605472733766141,
          #             "deto_referral_mining_daily_reward":"25000",
          #             "deto_total_reward_pool":"100000000",
          #             "deto_trade_mining_daily_reward":"75000",
          #             "kyc_deposit_limit":"20",
          #             "kyc_withdrawal_limit":"2",
          #             "under_maintenance":"false"
          #         },
          #         "success":true
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.safe_integer_product(result, 'server_time', 0.001)
  
      def fetch_status(self, params={}):
          response = self.publicGetSettings(params)
          result = self.safe_value(response, 'result', {})
          underMaintenance = self.safe_value(result, 'under_maintenance')
          status = 'maintenance' if (underMaintenance == 'true') else 'ok'
          updated = self.safe_integer_product(result, 'server_time', 0.001)
          self.status = self.extend(self.status, {
              'status': status,
              'updated': updated,
          })
          return self.status
  
      def fetch_currencies(self, params={}):
          response = self.publicGetAssets(params)
          #
          #     {
          #         "result":[
          #             {
          #                 "base_withdrawal_fee":"0.0005",
          #                 "deposit_status":"enabled",
          #                 "id":2,
          #                 "interest_credit":true,
          #                 "interest_slabs":[
          #                     {"limit":"0.1","rate":"0"},
          #                     {"limit":"1","rate":"0.05"},
          #                     {"limit":"5","rate":"0.075"},
          #                     {"limit":"10","rate":"0.1"},
          #                     {"limit":"9999999999999999","rate":"0"}
          #                 ],
          #                 "kyc_deposit_limit":"10",
          #                 "kyc_withdrawal_limit":"2",
          #                 "min_withdrawal_amount":"0.001",
          #                 "minimum_precision":4,
          #                 "name":"Bitcoin",
          #                 "precision":8,
          #                 "sort_priority":1,
          #                 "symbol":"BTC",
          #                 "variable_withdrawal_fee":"0",
          #                 "withdrawal_status":"enabled"
          #             },
          #         ],
          #         "success":true
          #     }
          #
          currencies = self.safe_value(response, 'result', [])
          result = {}
          for i in range(0, len(currencies)):
              currency = currencies[i]
              id = self.safe_string(currency, 'symbol')
              numericId = self.safe_integer(currency, 'id')
              code = self.safe_currency_code(id)
              depositStatus = self.safe_string(currency, 'deposit_status')
              withdrawalStatus = self.safe_string(currency, 'withdrawal_status')
              depositsEnabled = (depositStatus == 'enabled')
              withdrawalsEnabled = (withdrawalStatus == 'enabled')
              active = depositsEnabled and withdrawalsEnabled
              precision = self.safe_integer(currency, 'precision')
              result[code] = {
                  'id': id,
                  'numericId': numericId,
                  'code': code,
                  'name': self.safe_string(currency, 'name'),
                  'info': currency,  # the original payload
                  'active': active,
                  'fee': self.safe_number(currency, 'base_withdrawal_fee'),
                  'precision': 1 / math.pow(10, precision),
                  'limits': {
                      'amount': {'min': None, 'max': None},
                      'withdraw': {
                          'min': self.safe_number(currency, 'min_withdrawal_amount'),
                          'max': None,
                      },
                  },
              }
          return result
  
      def load_markets(self, reload=False, params={}):
          markets = super(delta, self).load_markets(reload, params)
          currenciesByNumericId = self.safe_value(self.options, 'currenciesByNumericId')
          if (currenciesByNumericId is None) or reload:
              self.options['currenciesByNumericId'] = self.index_by(self.currencies, 'numericId')
          marketsByNumericId = self.safe_value(self.options, 'marketsByNumericId')
          if (marketsByNumericId is None) or reload:
              self.options['marketsByNumericId'] = self.index_by(self.markets, 'numericId')
          return markets
  
      def fetch_markets(self, params={}):
          response = self.publicGetProducts(params)
          #
          #     {
          #         "meta":{
          #             "after":null,
          #             "before":null,
          #             "limit":100,
          #             "total_count":81
          #         },
          #         "result":[
          #             {
          #                 "annualized_funding":"5.475000000000000000",
          #                 "is_quanto":false,
          #                 "ui_config":{
          #                     "default_trading_view_candle":"15",
          #                     "leverage_slider_values":[1,3,5,10,25,50],
          #                     "price_clubbing_values":[0.001,0.005,0.05,0.1,0.5,1,5],
          #                     "show_bracket_orders":false,
          #                     "sort_priority":29,
          #                     "tags":[]
          #                 },
          #                 "basis_factor_max_limit":"0.15",
          #                 "symbol":"P-LINK-D-151120",
          #                 "id":1584,
          #                 "default_leverage":"5.000000000000000000",
          #                 "maker_commission_rate":"0.0005",
          #                 "contract_unit_currency":"LINK",
          #                 "strike_price":"12.507948",
          #                 "settling_asset":{
          #                     # asset structure
          #                 },
          #                 "auction_start_time":null,
          #                 "auction_finish_time":null,
          #                 "settlement_time":"2020-11-15T12:00:00Z",
          #                 "launch_time":"2020-11-14T11:55:05Z",
          #                 "spot_index":{
          #                     # index structure
          #                 },
          #                 "trading_status":"operational",
          #                 "tick_size":"0.001",
          #                 "position_size_limit":100000,
          #                 "notional_type":"vanilla",  # vanilla, inverse
          #                 "price_band":"0.4",
          #                 "barrier_price":null,
          #                 "description":"Daily LINK PUT options quoted in USDT and settled in USDT",
          #                 "insurance_fund_margin_contribution":"1",
          #                 "quoting_asset":{
          #                     # asset structure
          #                 },
          #                 "liquidation_penalty_factor":"0.2",
          #                 "product_specs":{"max_volatility":3,"min_volatility":0.3,"spot_price_band":"0.40"},
          #                 "initial_margin_scaling_factor":"0.0001",
          #                 "underlying_asset":{
          #                     # asset structure
          #                 },
          #                 "state":"live",
          #                 "contract_value":"1",
          #                 "initial_margin":"2",
          #                 "impact_size":5000,
          #                 "settlement_price":null,
          #                 "contract_type":"put_options",  # put_options, call_options, move_options, perpetual_futures, interest_rate_swaps, futures, spreads
          #                 "taker_commission_rate":"0.0005",
          #                 "maintenance_margin":"1",
          #                 "short_description":"LINK Daily PUT Options",
          #                 "maintenance_margin_scaling_factor":"0.00005",
          #                 "funding_method":"mark_price",
          #                 "max_leverage_notional":"20000"
          #             },
          #         ],
          #         "success":true
          #     }
          #
          markets = self.safe_value(response, 'result', [])
          result = []
          for i in range(0, len(markets)):
              market = markets[i]
              type = self.safe_string(market, 'contract_type')
              # settlingAsset = self.safe_value(market, 'settling_asset', {})
              quotingAsset = self.safe_value(market, 'quoting_asset', {})
              underlyingAsset = self.safe_value(market, 'underlying_asset', {})
              baseId = self.safe_string(underlyingAsset, 'symbol')
              quoteId = self.safe_string(quotingAsset, 'symbol')
              id = self.safe_string(market, 'symbol')
              numericId = self.safe_integer(market, 'id')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = id
              swap = False
              future = False
              option = False
              if type == 'perpetual_futures':
                  type = 'swap'
                  swap = True
                  future = False
                  option = False
                  if id.find('_') < 0:
                      symbol = base + '/' + quote
              elif (type == 'call_options') or (type == 'put_options') or (type == 'move_options'):
                  type = 'option'
                  swap = False
                  option = True
                  future = False
              elif type == 'futures':
                  type = 'future'
                  swap = False
                  option = False
                  future = True
              precision = {
                  'amount': 1.0,  # number of contracts
                  'price': self.safe_number(market, 'tick_size'),
              }
              limits = {
                  'amount': {
                      'min': 1.0,
                      'max': self.safe_number(market, 'position_size_limit'),
                  },
                  'price': {
                      'min': precision['price'],
                      'max': None,
                  },
                  'cost': {
                      'min': self.safe_number(market, 'min_size'),
                      'max': None,
                  },
              }
              state = self.safe_string(market, 'state')
              active = (state == 'live')
              maker = self.safe_number(market, 'maker_commission_rate')
              taker = self.safe_number(market, 'taker_commission_rate')
              result.append({
                  'id': id,
                  'numericId': numericId,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'type': type,
                  'spot': False,
                  'option': option,
                  'swap': swap,
                  'future': future,
                  'maker': maker,
                  'taker': taker,
                  'precision': precision,
                  'limits': limits,
                  'info': market,
                  'active': active,
              })
          return result
  
      def parse_ticker(self, ticker, market=None):
          #
          # fetchTicker, fetchTickers
          #
          #     {
          #         "close":15837.5,
          #         "high":16354,
          #         "low":15751.5,
          #         "mark_price":"15820.100867",
          #         "open":16140.5,
          #         "product_id":139,
          #         "size":640552,
          #         "spot_price":"15827.050000000001",
          #         "symbol":"BTCUSDT",
          #         "timestamp":1605373550208262,
          #         "turnover":10298630.3735,
          #         "turnover_symbol":"USDT",
          #         "turnover_usd":10298630.3735,
          #         "volume":640.5520000000001
          #     }
          #
          timestamp = self.safe_integer_product(ticker, 'timestamp', 0.001)
          marketId = self.safe_string(ticker, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          last = self.safe_number(ticker, 'close')
          open = self.safe_number(ticker, 'open')
          baseVolume = self.safe_number(ticker, 'volume')
          quoteVolume = self.safe_number(ticker, 'turnover')
          vwap = self.vwap(baseVolume, quoteVolume)
          return self.safe_ticker({
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_number(ticker, 'high'),
              'low': self.safe_number(ticker, 'low'),
              'bid': None,
              'bidVolume': None,
              'ask': None,
              'askVolume': None,
              'vwap': vwap,
              'open': open,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': None,
              'percentage': None,
              'average': None,
              'baseVolume': baseVolume,
              'quoteVolume': quoteVolume,
              'info': ticker,
          }, market)
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          response = self.publicGetTickersSymbol(self.extend(request, params))
          #
          #     {
          #         "result":{
          #             "close":15837.5,
          #             "high":16354,
          #             "low":15751.5,
          #             "mark_price":"15820.100867",
          #             "open":16140.5,
          #             "product_id":139,
          #             "size":640552,
          #             "spot_price":"15827.050000000001",
          #             "symbol":"BTCUSDT",
          #             "timestamp":1605373550208262,
          #             "turnover":10298630.3735,
          #             "turnover_symbol":"USDT",
          #             "turnover_usd":10298630.3735,
          #             "volume":640.5520000000001
          #         },
          #         "success":true
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.parse_ticker(result, market)
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          response = self.publicGetTickers(params)
          #
          #     {
          #         "result":[
          #             {
          #                 "close":0.003966,
          #                 "high":0.004032,
          #                 "low":0.003606,
          #                 "mark_price":"0.00396328",
          #                 "open":0.003996,
          #                 "product_id":1327,
          #                 "size":6242,
          #                 "spot_price":"0.0039555",
          #                 "symbol":"AAVEBTC",
          #                 "timestamp":1605374143864107,
          #                 "turnover":23.997904999999996,
          #                 "turnover_symbol":"BTC",
          #                 "turnover_usd":387957.4544782897,
          #                 "volume":6242
          #             },
          #         ],
          #         "success":true
          #     }
          #
          tickers = self.safe_value(response, 'result', [])
          result = {}
          for i in range(0, len(tickers)):
              ticker = self.parse_ticker(tickers[i])
              symbol = ticker['symbol']
              result[symbol] = ticker
          return self.filter_by_array(result, 'symbol', symbols)
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          request = {
              'symbol': self.market_id(symbol),
          }
          if limit is not None:
              request['depth'] = limit
          response = self.publicGetL2orderbookSymbol(self.extend(request, params))
          #
          #     {
          #         "result":{
          #             "buy":[
          #                 {"price":"15814.0","size":912},
          #                 {"price":"15813.5","size":1279},
          #                 {"price":"15813.0","size":1634},
          #             ],
          #             "sell":[
          #                 {"price":"15814.5","size":625},
          #                 {"price":"15815.0","size":982},
          #                 {"price":"15815.5","size":1328},
          #             ],
          #             "symbol":"BTCUSDT"
          #         },
          #         "success":true
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return self.parse_order_book(result, symbol, None, 'buy', 'sell', 'price', 'size')
  
      def parse_trade(self, trade, market=None):
          #
          # public fetchTrades
          #
          #     {
          #         "buyer_role":"maker",
          #         "price":"15896.5",
          #         "seller_role":"taker",
          #         "size":241,
          #         "symbol":"BTCUSDT",
          #         "timestamp":1605376684714595
          #     }
          #
          # private fetchMyTrades
          #
          #     {
          #         "commission":"0.008335000000000000",
          #         "created_at":"2020-11-16T19:07:19Z",
          #         "fill_type":"normal",
          #         "id":"e7ff05c233a74245b72381f8dd91d1ce",
          #         "meta_data":{
          #             "effective_commission_rate":"0.0005",
          #             "order_price":"16249",
          #             "order_size":1,
          #             "order_type":"market_order",
          #             "order_unfilled_size":0,
          #             "trading_fee_credits_used":"0"
          #         },
          #         "order_id":"152999629",
          #         "price":"16669",
          #         "product":{
          #             "contract_type":"perpetual_futures",
          #             "contract_unit_currency":"BTC",
          #             "contract_value":"0.001",
          #             "id":139,
          #             "notional_type":"vanilla",
          #             "quoting_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
          #             "settling_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
          #             "symbol":"BTCUSDT",
          #             "tick_size":"0.5",
          #             "underlying_asset":{"minimum_precision":4,"precision":8,"symbol":"BTC"}
          #         },
          #         "product_id":139,
          #         "role":"taker",
          #         "side":"sell",
          #         "size":1
          #     }
          #
          id = self.safe_string(trade, 'id')
          orderId = self.safe_string(trade, 'order_id')
          timestamp = self.parse8601(self.safe_string(trade, 'created_at'))
          timestamp = self.safe_integer_product(trade, 'timestamp', 0.001, timestamp)
          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))
          product = self.safe_value(trade, 'product', {})
          marketId = self.safe_string(product, 'symbol')
          symbol = self.safe_symbol(marketId, market)
          sellerRole = self.safe_string(trade, 'seller_role')
          side = self.safe_string(trade, 'side')
          if side is None:
              if sellerRole == 'taker':
                  side = 'sell'
              elif sellerRole == 'maker':
                  side = 'buy'
          takerOrMaker = self.safe_string(trade, 'role')
          metaData = self.safe_value(trade, 'meta_data', {})
          type = self.safe_string(metaData, 'order_type')
          if type is not None:
              type = type.replace('_order', '')
          feeCost = self.safe_number(trade, 'commission')
          fee = None
          if feeCost is not None:
              settlingAsset = self.safe_value(product, 'settling_asset', {})
              feeCurrencyId = self.safe_string(settlingAsset, 'symbol')
              feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
              fee = {
                  'cost': feeCost,
                  'currency': feeCurrencyCode,
              }
          return {
              'id': id,
              'order': orderId,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'type': type,
              'side': side,
              'price': price,
              'amount': amount,
              'cost': cost,
              'takerOrMaker': takerOrMaker,
              'fee': fee,
              'info': trade,
          }
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          response = self.publicGetTradesSymbol(self.extend(request, params))
          #
          #     {
          #         "result":[
          #             {
          #                 "buyer_role":"maker",
          #                 "price":"15896.5",
          #                 "seller_role":"taker",
          #                 "size":241,
          #                 "symbol":"BTCUSDT",
          #                 "timestamp":1605376684714595
          #             }
          #         ],
          #         "success":true
          #     }
          #
          result = self.safe_value(response, 'result', [])
          return self.parse_trades(result, market, since, limit)
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          #     {
          #         "time":1605393120,
          #         "open":15989,
          #         "high":15989,
          #         "low":15987.5,
          #         "close":15987.5,
          #         "volume":565
          #     }
          #
          return [
              self.safe_timestamp(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 fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
              'resolution': self.timeframes[timeframe],
          }
          duration = self.parse_timeframe(timeframe)
          limit = limit if limit else 2000  # max 2000
          if since is None:
              end = self.seconds()
              request['end'] = end
              request['start'] = end - limit * duration
          else:
              start = int(since / 1000)
              request['start'] = start
              request['end'] = self.sum(start, limit * duration)
          response = self.publicGetHistoryCandles(self.extend(request, params))
          #
          #     {
          #         "success":true,
          #         "result":[
          #             {"time":1605393120,"open":15989,"high":15989,"low":15987.5,"close":15987.5,"volume":565},
          #             {"time":1605393180,"open":15966,"high":15966,"low":15959,"close":15959,"volume":24},
          #             {"time":1605393300,"open":15973,"high":15973,"low":15973,"close":15973,"volume":1288},
          #         ]
          #     }
          #
          result = self.safe_value(response, 'result', [])
          return self.parse_ohlcvs(result, market, timeframe, since, limit)
  
      def fetch_balance(self, params={}):
          self.load_markets()
          response = self.privateGetWalletBalances(params)
          #
          #     {
          #         "result":[
          #             {
          #                 "asset_id":1,
          #                 "available_balance":"0",
          #                 "balance":"0",
          #                 "commission":"0",
          #                 "id":154883,
          #                 "interest_credit":"0",
          #                 "order_margin":"0",
          #                 "pending_referral_bonus":"0",
          #                 "pending_trading_fee_credit":"0",
          #                 "position_margin":"0",
          #                 "trading_fee_credit":"0",
          #                 "user_id":22142
          #             },
          #         ],
          #         "success":true
          #     }
          #
          balances = self.safe_value(response, 'result', [])
          result = {'info': response}
          currenciesByNumericId = self.safe_value(self.options, 'currenciesByNumericId', {})
          for i in range(0, len(balances)):
              balance = balances[i]
              currencyId = self.safe_string(balance, 'asset_id')
              currency = self.safe_value(currenciesByNumericId, currencyId)
              code = currencyId if (currency is None) else currency['code']
              account = self.account()
              account['total'] = self.safe_string(balance, 'balance')
              account['free'] = self.safe_string(balance, 'available_balance')
              result[code] = account
          return self.parse_balance(result)
  
      def fetch_position(self, symbol, params=None):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'product_id': market['numericId'],
          }
          response = self.privateGetPositions(self.extend(request, params))
          #
          #     {
          #         "result":{
          #             "entry_price":null,
          #             "size":0,
          #             "timestamp":1605454074268079
          #         },
          #         "success":true
          #     }
          #
          result = self.safe_value(response, 'result', {})
          return result
  
      def fetch_positions(self, symbols=None, params={}):
          self.load_markets()
          response = self.privateGetPositionsMargined(params)
          #
          #     {
          #         "success": True,
          #         "result": [
          #             {
          #                 "user_id": 0,
          #                 "size": 0,
          #                 "entry_price": "string",
          #                 "margin": "string",
          #                 "liquidation_price": "string",
          #                 "bankruptcy_price": "string",
          #                 "adl_level": 0,
          #                 "product_id": 0
          #             }
          #         ]
          #     }
          #
          result = self.safe_value(response, 'result', [])
          return result
  
      def parse_order_status(self, status):
          statuses = {
              'open': 'open',
              'pending': 'open',
              'closed': 'closed',
              'cancelled': 'canceled',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_order(self, order, market=None):
          #
          # createOrder, cancelOrder, editOrder, fetchOpenOrders, fetchClosedOrders
          #
          #     {
          #         "average_fill_price":null,
          #         "bracket_order":null,
          #         "bracket_stop_loss_limit_price":null,
          #         "bracket_stop_loss_price":null,
          #         "bracket_take_profit_limit_price":null,
          #         "bracket_take_profit_price":null,
          #         "bracket_trail_amount":null,
          #         "cancellation_reason":null,
          #         "client_order_id":null,
          #         "close_on_trigger":"false",
          #         "commission":"0",
          #         "created_at":"2020-11-16T02:38:26Z",
          #         "id":152870626,
          #         "limit_price":"10000",
          #         "meta_data":{"source":"api"},
          #         "order_type":"limit_order",
          #         "paid_commission":"0",
          #         "product_id":139,
          #         "reduce_only":false,
          #         "side":"buy",
          #         "size":0,
          #         "state":"open",
          #         "stop_order_type":null,
          #         "stop_price":null,
          #         "stop_trigger_method":"mark_price",
          #         "time_in_force":"gtc",
          #         "trail_amount":null,
          #         "unfilled_size":0,
          #         "user_id":22142
          #     }
          #
          id = self.safe_string(order, 'id')
          clientOrderId = self.safe_string(order, 'client_order_id')
          timestamp = self.parse8601(self.safe_string(order, 'created_at'))
          marketId = self.safe_string(order, 'product_id')
          marketsByNumericId = self.safe_value(self.options, 'marketsByNumericId', {})
          market = self.safe_value(marketsByNumericId, marketId, market)
          symbol = marketId if (market is None) else market['symbol']
          status = self.parse_order_status(self.safe_string(order, 'state'))
          side = self.safe_string(order, 'side')
          type = self.safe_string(order, 'order_type')
          type = type.replace('_order', '')
          price = self.safe_string(order, 'limit_price')
          amount = self.safe_string(order, 'size')
          remaining = self.safe_string(order, 'unfilled_size')
          average = self.safe_string(order, 'average_fill_price')
          fee = None
          feeCost = self.safe_number(order, 'paid_commission')
          if feeCost is not None:
              feeCurrencyCode = None
              if market is not None:
                  settlingAsset = self.safe_value(market['info'], 'settling_asset', {})
                  feeCurrencyId = self.safe_string(settlingAsset, 'symbol')
                  feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
              fee = {
                  'cost': feeCost,
                  'currency': feeCurrencyCode,
              }
          return self.safe_order2({
              'info': order,
              'id': id,
              'clientOrderId': clientOrderId,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': None,
              'symbol': symbol,
              'type': type,
              'side': side,
              'price': price,
              'amount': amount,
              'cost': None,
              'average': average,
              'filled': None,
              'remaining': remaining,
              'status': status,
              'fee': fee,
              'trades': None,
          }, market)
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          orderType = type + '_order'
          market = self.market(symbol)
          request = {
              'product_id': market['numericId'],
              # 'limit_price': self.price_to_precision(symbol, price),
              'size': self.amount_to_precision(symbol, amount),
              'side': side,
              'order_type': orderType,
              # 'client_order_id': 'string',
              # 'time_in_force': 'gtc',  # gtc, ioc, fok
              # 'post_only': 'false',  # 'true',
              # 'reduce_only': 'false',  # 'true',
          }
          if type == 'limit':
              request['limit_price'] = self.price_to_precision(symbol, price)
          clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_order_id')
          params = self.omit(params, ['clientOrderId', 'client_order_id'])
          if clientOrderId is not None:
              request['client_order_id'] = clientOrderId
          response = self.privatePostOrders(self.extend(request, params))
          #
          #     {
          #         "result":{
          #             "average_fill_price":null,
          #             "bracket_order":null,
          #             "bracket_stop_loss_limit_price":null,
          #             "bracket_stop_loss_price":null,
          #             "bracket_take_profit_limit_price":null,
          #             "bracket_take_profit_price":null,
          #             "bracket_trail_amount":null,
          #             "cancellation_reason":null,
          #             "client_order_id":null,
          #             "close_on_trigger":"false",
          #             "commission":"0",
          #             "created_at":"2020-11-16T02:38:26Z",
          #             "id":152870626,
          #             "limit_price":"10000",
          #             "meta_data":{"source":"api"},
          #             "order_type":"limit_order",
          #             "paid_commission":"0",
          #             "product_id":139,
          #             "reduce_only":false,
          #             "side":"buy",
          #             "size":0,
          #             "state":"open",
          #             "stop_order_type":null,
          #             "stop_price":null,
          #             "stop_trigger_method":"mark_price",
          #             "time_in_force":"gtc",
          #             "trail_amount":null,
          #             "unfilled_size":0,
          #             "user_id":22142
          #         },
          #         "success":true
          #     }
          #
          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 = {
              'id': int(id),
              'product_id': market['numericId'],
              # 'limit_price': self.price_to_precision(symbol, price),
              # 'size': self.amount_to_precision(symbol, amount),
          }
          if amount is not None:
              request['size'] = int(self.amount_to_precision(symbol, amount))
          if price is not None:
              request['limit_price'] = self.price_to_precision(symbol, price)
          response = self.privatePutOrders(self.extend(request, params))
          #
          #     {
          #         "success": True,
          #         "result": {
          #             "id": "ashb1212",
          #             "product_id": 27,
          #             "limit_price": "9200",
          #             "side": "buy",
          #             "size": 100,
          #             "unfilled_size": 50,
          #             "user_id": 1,
          #             "order_type": "limit_order",
          #             "state": "open",
          #             "created_at": "..."
          #         }
          #     }
          #
          result = self.safe_value(response, 'result')
          return self.parse_order(result, market)
  
      def cancel_order(self, id, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          request = {
              'id': int(id),
              'product_id': market['numericId'],
          }
          response = self.privateDeleteOrders(self.extend(request, params))
          #
          #     {
          #         "result":{
          #             "average_fill_price":null,
          #             "bracket_order":null,
          #             "bracket_stop_loss_limit_price":null,
          #             "bracket_stop_loss_price":null,
          #             "bracket_take_profit_limit_price":null,
          #             "bracket_take_profit_price":null,
          #             "bracket_trail_amount":null,
          #             "cancellation_reason":"cancelled_by_user",
          #             "client_order_id":null,
          #             "close_on_trigger":"false",
          #             "commission":"0",
          #             "created_at":"2020-11-16T02:38:26Z",
          #             "id":152870626,
          #             "limit_price":"10000",
          #             "meta_data":{"source":"api"},
          #             "order_type":"limit_order",
          #             "paid_commission":"0",
          #             "product_id":139,
          #             "reduce_only":false,
          #             "side":"buy",
          #             "size":0,
          #             "state":"cancelled",
          #             "stop_order_type":null,
          #             "stop_price":null,
          #             "stop_trigger_method":"mark_price",
          #             "time_in_force":"gtc",
          #             "trail_amount":null,
          #             "unfilled_size":0,
          #             "user_id":22142
          #         },
          #         "success":true
          #     }
          #
          result = self.safe_value(response, 'result')
          return self.parse_order(result, market)
  
      def cancel_all_orders(self, symbol=None, params={}):
          if symbol is None:
              raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
          self.load_markets()
          market = self.market(symbol)
          request = {
              'product_id': market['numericId'],
              # 'cancel_limit_orders': 'true',
              # 'cancel_stop_orders': 'true',
          }
          response = self.privateDeleteOrdersAll(self.extend(request, params))
          #
          #     {
          #         "result":{},
          #         "success":true
          #     }
          #
          return response
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          return self.fetch_orders_with_method('privateGetOrders', symbol, since, limit, params)
  
      def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          return self.fetch_orders_with_method('privateGetOrdersHistory', symbol, since, limit, params)
  
      def fetch_orders_with_method(self, method, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              # 'product_ids': market['id'],  # comma-separated
              # 'contract_types': types,  # comma-separated, futures, perpetual_futures, call_options, put_options, interest_rate_swaps, move_options, spreads
              # 'order_types': types,  # comma-separated, market, limit, stop_market, stop_limit, all_stop
              # 'start_time': since * 1000,
              # 'end_time': self.microseconds(),
              # 'after': string,  # after cursor for pagination
              # 'before': string,  # before cursor for pagination
              # 'page_size': limit,  # number of records per page
          }
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['product_ids'] = market['numericId']  # accepts a comma-separated list of ids
          if since is not None:
              request['start_time'] = str(since) + '000'
          if limit is not None:
              request['page_size'] = limit
          response = getattr(self, method)(self.extend(request, params))
          #
          #     {
          #         "success": True,
          #         "result": [
          #             {
          #                 "id": "ashb1212",
          #                 "product_id": 27,
          #                 "limit_price": "9200",
          #                 "side": "buy",
          #                 "size": 100,
          #                 "unfilled_size": 50,
          #                 "user_id": 1,
          #                 "order_type": "limit_order",
          #                 "state": "open",
          #                 "created_at": "..."
          #             }
          #         ],
          #         "meta": {
          #             "after": "string",
          #             "before": "string"
          #         }
          #     }
          #
          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()
          request = {
              # 'product_ids': market['id'],  # comma-separated
              # 'contract_types': types,  # comma-separated, futures, perpetual_futures, call_options, put_options, interest_rate_swaps, move_options, spreads
              # 'start_time': since * 1000,
              # 'end_time': self.microseconds(),
              # 'after': string,  # after cursor for pagination
              # 'before': string,  # before cursor for pagination
              # 'page_size': limit,  # number of records per page
          }
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['product_ids'] = market['numericId']  # accepts a comma-separated list of ids
          if since is not None:
              request['start_time'] = str(since) + '000'
          if limit is not None:
              request['page_size'] = limit
          response = self.privateGetFills(self.extend(request, params))
          #
          #     {
          #         "meta":{
          #             "after":null,
          #             "before":null,
          #             "limit":10,
          #             "total_count":2
          #         },
          #         "result":[
          #             {
          #                 "commission":"0.008335000000000000",
          #                 "created_at":"2020-11-16T19:07:19Z",
          #                 "fill_type":"normal",
          #                 "id":"e7ff05c233a74245b72381f8dd91d1ce",
          #                 "meta_data":{
          #                     "effective_commission_rate":"0.0005",
          #                     "order_price":"16249",
          #                     "order_size":1,
          #                     "order_type":"market_order",
          #                     "order_unfilled_size":0,
          #                     "trading_fee_credits_used":"0"
          #                 },
          #                 "order_id":"152999629",
          #                 "price":"16669",
          #                 "product":{
          #                     "contract_type":"perpetual_futures",
          #                     "contract_unit_currency":"BTC",
          #                     "contract_value":"0.001",
          #                     "id":139,
          #                     "notional_type":"vanilla",
          #                     "quoting_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
          #                     "settling_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
          #                     "symbol":"BTCUSDT",
          #                     "tick_size":"0.5",
          #                     "underlying_asset":{"minimum_precision":4,"precision":8,"symbol":"BTC"}
          #                 },
          #                 "product_id":139,
          #                 "role":"taker",
          #                 "side":"sell",
          #                 "size":1
          #             }
          #         ],
          #         "success":true
          #     }
          #
          result = self.safe_value(response, 'result', [])
          return self.parse_trades(result, market, since, limit)
  
      def fetch_ledger(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              # 'asset_id': currency['numericId'],
              # 'end_time': self.seconds(),
              # 'after': 'string',  # after cursor for pagination
              # 'before': 'string',  # before cursor for pagination
              # 'page_size': limit,
          }
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['asset_id'] = currency['numericId']
          if limit is not None:
              request['page_size'] = limit
          response = self.privateGetWalletTransactions(self.extend(request, params))
          #
          #     {
          #         "meta":{"after":null,"before":null,"limit":10,"total_count":1},
          #         "result":[
          #             {
          #                 "amount":"29.889184",
          #                 "asset_id":5,
          #                 "balance":"29.889184",
          #                 "created_at":"2020-11-15T21:25:01Z",
          #                 "meta_data":{
          #                     "deposit_id":3884,
          #                     "transaction_id":"0x41a60174849828530abb5008e98fc63c9b598288743ec4ba9620bcce900a3b8d"
          #                 },
          #                 "transaction_type":"deposit",
          #                 "user_id":22142,
          #                 "uuid":"70bb5679da3c4637884e2dc63efaa846"
          #             }
          #         ],
          #         "success":true
          #     }
          #
          result = self.safe_value(response, 'result', [])
          return self.parse_ledger(result, currency, since, limit)
  
      def parse_ledger_entry_type(self, type):
          types = {
              'pnl': 'pnl',
              'deposit': 'transaction',
              'withdrawal': 'transaction',
              'commission': 'fee',
              'conversion': 'trade',
              # 'perpetual_futures_funding': 'perpetual_futures_funding',
              # 'withdrawal_cancellation': 'withdrawal_cancellation',
              'referral_bonus': 'referral',
              'commission_rebate': 'rebate',
              # 'promo_credit': 'promo_credit',
          }
          return self.safe_string(types, type, type)
  
      def parse_ledger_entry(self, item, currency=None):
          #
          #     {
          #         "amount":"29.889184",
          #         "asset_id":5,
          #         "balance":"29.889184",
          #         "created_at":"2020-11-15T21:25:01Z",
          #         "meta_data":{
          #             "deposit_id":3884,
          #             "transaction_id":"0x41a60174849828530abb5008e98fc63c9b598288743ec4ba9620bcce900a3b8d"
          #         },
          #         "transaction_type":"deposit",
          #         "user_id":22142,
          #         "uuid":"70bb5679da3c4637884e2dc63efaa846"
          #     }
          #
          id = self.safe_string(item, 'uuid')
          direction = None
          account = None
          metaData = self.safe_value(item, 'meta_data', {})
          referenceId = self.safe_string(metaData, 'transaction_id')
          referenceAccount = None
          type = self.safe_string(item, 'transaction_type')
          if (type == 'deposit') or (type == 'commission_rebate') or (type == 'referral_bonus') or (type == 'pnl') or (type == 'withdrawal_cancellation') or (type == 'promo_credit'):
              direction = 'in'
          elif (type == 'withdrawal') or (type == 'commission') or (type == 'conversion') or (type == 'perpetual_futures_funding'):
              direction = 'out'
          type = self.parse_ledger_entry_type(type)
          currencyId = self.safe_integer(item, 'asset_id')
          currenciesByNumericId = self.safe_value(self.options, 'currenciesByNumericId')
          currency = self.safe_value(currenciesByNumericId, currencyId, currency)
          code = None if (currency is None) else currency['code']
          amount = self.safe_number(item, 'amount')
          timestamp = self.parse8601(self.safe_string(item, 'created_at'))
          after = self.safe_number(item, 'balance')
          before = max(0, after - amount)
          status = 'ok'
          return {
              'info': item,
              'id': id,
              'direction': direction,
              'account': account,
              'referenceId': referenceId,
              'referenceAccount': referenceAccount,
              'type': type,
              'currency': code,
              'amount': amount,
              'before': before,
              'after': after,
              'status': status,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'fee': None,
          }
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'asset_symbol': currency['id'],
          }
          response = self.privateGetDepositsAddress(self.extend(request, params))
          #
          #     {
          #         "success":true,
          #         "result":{
          #             "id":19628,
          #             "user_id":22142,
          #             "address":"0x0eda26523397534f814d553a065d8e46b4188e9a",
          #             "status":"active",
          #             "updated_at":"2020-11-15T20:25:53.000Z",
          #             "created_at":"2020-11-15T20:25:53.000Z",
          #             "asset_symbol":"USDT",
          #             "custodian":"onc"
          #         }
          #     }
          #
          result = self.safe_value(response, 'result', {})
          address = self.safe_string(result, 'address')
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'tag': None,
              'network': None,
              'info': response,
          }
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          requestPath = '/' + self.version + '/' + self.implode_params(path, params)
          url = self.urls['api'][api] + requestPath
          query = self.omit(params, self.extract_params(path))
          if api == 'public':
              if query:
                  url += '?' + self.urlencode(query)
          elif api == 'private':
              self.check_required_credentials()
              timestamp = str(self.seconds())
              headers = {
                  'api-key': self.apiKey,
                  'timestamp': timestamp,
              }
              auth = method + timestamp + requestPath
              if (method == 'GET') or (method == 'DELETE'):
                  if query:
                      queryString = '?' + self.urlencode(query)
                      auth += queryString
                      url += queryString
              else:
                  body = self.json(query)
                  auth += body
                  headers['Content-Type'] = 'application/json'
              signature = self.hmac(self.encode(auth), self.encode(self.secret))
              headers['signature'] = 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
          #
          # {"error":{"code":"insufficient_margin","context":{"available_balance":"0.000000000000000000","required_additional_balance":"1.618626000000000000000000000"}},"success":false}
          #
          error = self.safe_value(response, 'error', {})
          errorCode = self.safe_string(error, 'code')
          if errorCode is not None:
              feedback = self.id + ' ' + body
              self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
              self.throw_broadly_matched_exception(self.exceptions['broad'], errorCode, feedback)
              raise ExchangeError(feedback)  # unknown message
  