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
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import PermissionDenied
  from ccxt.base.errors import ArgumentsRequired
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidAddress
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import DDoSProtection
  from ccxt.base.errors import ExchangeNotAvailable
  
  
  class bitpanda(Exchange):
  
      def describe(self):
          return self.deep_extend(super(bitpanda, self).describe(), {
              'id': 'bitpanda',
              'name': 'Bitpanda Pro',
              'countries': ['AT'],  # Austria
              'rateLimit': 300,
              'version': 'v1',
              # new metainfo interface
              'has': {
                  'CORS': False,
                  'publicAPI': True,
                  'privateAPI': True,
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'cancelOrders': True,
                  'createDepositAddress': True,
                  'createOrder': True,
                  'fetchBalance': True,
                  'fetchClosedOrders': True,
                  'fetchCurrencies': True,
                  'fetchDeposits': True,
                  'fetchDepositAddress': True,
                  'fetchMarkets': True,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': True,
                  'fetchOrder': True,
                  'fetchOrderBook': True,
                  'fetchOrderTrades': True,
                  'fetchTime': True,
                  'fetchTrades': True,
                  'fetchTradingFees': True,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchWithdrawals': True,
              },
              'timeframes': {
                  '1m': '1/MINUTES',
                  '5m': '5/MINUTES',
                  '15m': '15/MINUTES',
                  '30m': '30/MINUTES',
                  '1h': '1/HOURS',
                  '4h': '4/HOURS',
                  '1d': '1/DAYS',
                  '1w': '1/WEEKS',
                  '1M': '1/MONTHS',
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/51840849/87591171-9a377d80-c6f0-11ea-94ac-97a126eac3bc.jpg',
                  'api': {
                      'public': 'https://api.exchange.bitpanda.com/public',
                      'private': 'https://api.exchange.bitpanda.com/public',
                  },
                  'www': 'https://www.bitpanda.com/en/pro',
                  'doc': [
                      'https://developers.bitpanda.com/exchange/',
                  ],
                  'fees': 'https://www.bitpanda.com/en/pro/fees',
              },
              'api': {
                  'public': {
                      'get': [
                          'currencies',
                          'candlesticks/{instrument_code}',
                          'fees',
                          'instruments',
                          'order-book/{instrument_code}',
                          'market-ticker',
                          'market-ticker/{instrument_code}',
                          'price-ticks/{instrument_code}',
                          'time',
                      ],
                  },
                  'private': {
                      'get': [
                          'account/balances',
                          'account/deposit/crypto/{currency_code}',
                          'account/deposit/fiat/EUR',
                          'account/deposits',
                          'account/deposits/bitpanda',
                          'account/withdrawals',
                          'account/withdrawals/bitpanda',
                          'account/fees',
                          'account/orders',
                          'account/orders/{order_id}',
                          'account/orders/{order_id}/trades',
                          'account/trades',
                          'account/trades/{trade_id}',
                          'account/trading-volume',
                      ],
                      'post': [
                          'account/deposit/crypto',
                          'account/withdraw/crypto',
                          'account/withdraw/fiat',
                          'account/fees',
                          'account/orders',
                      ],
                      'delete': [
                          'account/orders',
                          'account/orders/{order_id}',
                          'account/orders/client/{client_id}',
                      ],
                  },
              },
              'fees': {
                  'trading': {
                      'tierBased': True,
                      'percentage': True,
                      'taker': 0.15 / 100,
                      'maker': 0.10 / 100,
                      'tiers': [
                          # volume in BTC
                          {
                              '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],
                              ],
                          },
                      ],
                  },
              },
              'requiredCredentials': {
                  'apiKey': True,
                  'secret': False,
              },
              # exchange-specific options
              'options': {
                  'fetchTradingFees': {
                      'method': 'fetchPrivateTradingFees',  # or 'fetchPublicTradingFees'
                  },
              },
              'exceptions': {
                  'exact': {
                      'INVALID_CLIENT_UUID': InvalidOrder,
                      'ORDER_NOT_FOUND': OrderNotFound,
                      'ONLY_ONE_ERC20_ADDRESS_ALLOWED': InvalidAddress,
                      'DEPOSIT_ADDRESS_NOT_USED': InvalidAddress,
                      'INVALID_CREDENTIALS': AuthenticationError,
                      'MISSING_CREDENTIALS': AuthenticationError,
                      'INVALID_APIKEY': AuthenticationError,
                      'INVALID_SCOPES': AuthenticationError,
                      'INVALID_SUBJECT': AuthenticationError,
                      'INVALID_ISSUER': AuthenticationError,
                      'INVALID_AUDIENCE': AuthenticationError,
                      'INVALID_DEVICE_ID': AuthenticationError,
                      'INVALID_IP_RESTRICTION': AuthenticationError,
                      'APIKEY_REVOKED': AuthenticationError,
                      'APIKEY_EXPIRED': AuthenticationError,
                      'SYNCHRONIZER_TOKEN_MISMATCH': AuthenticationError,
                      'SESSION_EXPIRED': AuthenticationError,
                      'INTERNAL_ERROR': AuthenticationError,
                      'CLIENT_IP_BLOCKED': PermissionDenied,
                      'MISSING_PERMISSION': PermissionDenied,
                      'ILLEGAL_CHARS': BadRequest,
                      'UNSUPPORTED_MEDIA_TYPE': BadRequest,
                      'ACCOUNT_HISTORY_TIME_RANGE_TOO_BIG': BadRequest,
                      'CANDLESTICKS_TIME_RANGE_TOO_BIG': BadRequest,
                      'INVALID_INSTRUMENT_CODE': BadRequest,
                      'INVALID_ORDER_TYPE': BadRequest,
                      'INVALID_UNIT': BadRequest,
                      'INVALID_PERIOD': BadRequest,
                      'INVALID_TIME': BadRequest,
                      'INVALID_DATE': BadRequest,
                      'INVALID_CURRENCY': BadRequest,
                      'INVALID_AMOUNT': BadRequest,
                      'INVALID_PRICE': BadRequest,
                      'INVALID_LIMIT': BadRequest,
                      'INVALID_QUERY': BadRequest,
                      'INVALID_CURSOR': BadRequest,
                      'INVALID_ACCOUNT_ID': BadRequest,
                      'INVALID_SIDE': InvalidOrder,
                      'INVALID_ACCOUNT_HISTORY_FROM_TIME': BadRequest,
                      'INVALID_ACCOUNT_HISTORY_MAX_PAGE_SIZE': BadRequest,
                      'INVALID_ACCOUNT_HISTORY_TIME_PERIOD': BadRequest,
                      'INVALID_ACCOUNT_HISTORY_TO_TIME': BadRequest,
                      'INVALID_CANDLESTICKS_GRANULARITY': BadRequest,
                      'INVALID_CANDLESTICKS_UNIT': BadRequest,
                      'INVALID_ORDER_BOOK_DEPTH': BadRequest,
                      'INVALID_ORDER_BOOK_LEVEL': BadRequest,
                      'INVALID_PAGE_CURSOR': BadRequest,
                      'INVALID_TIME_RANGE': BadRequest,
                      'INVALID_TRADE_ID': BadRequest,
                      'INVALID_UI_ACCOUNT_SETTINGS': BadRequest,
                      'NEGATIVE_AMOUNT': InvalidOrder,
                      'NEGATIVE_PRICE': InvalidOrder,
                      'MIN_SIZE_NOT_SATISFIED': InvalidOrder,
                      'BAD_AMOUNT_PRECISION': InvalidOrder,
                      'BAD_PRICE_PRECISION': InvalidOrder,
                      'BAD_TRIGGER_PRICE_PRECISION': InvalidOrder,
                      'MAX_OPEN_ORDERS_EXCEEDED': BadRequest,
                      'MISSING_PRICE': InvalidOrder,
                      'MISSING_ORDER_TYPE': InvalidOrder,
                      'MISSING_SIDE': InvalidOrder,
                      'MISSING_CANDLESTICKS_PERIOD_PARAM': ArgumentsRequired,
                      'MISSING_CANDLESTICKS_UNIT_PARAM': ArgumentsRequired,
                      'MISSING_FROM_PARAM': ArgumentsRequired,
                      'MISSING_INSTRUMENT_CODE': ArgumentsRequired,
                      'MISSING_ORDER_ID': InvalidOrder,
                      'MISSING_TO_PARAM': ArgumentsRequired,
                      'MISSING_TRADE_ID': ArgumentsRequired,
                      'INVALID_ORDER_ID': OrderNotFound,
                      'NOT_FOUND': OrderNotFound,
                      'INSUFFICIENT_LIQUIDITY': InsufficientFunds,
                      'INSUFFICIENT_FUNDS': InsufficientFunds,
                      'NO_TRADING': ExchangeNotAvailable,
                      'SERVICE_UNAVAILABLE': ExchangeNotAvailable,
                      'GATEWAY_TIMEOUT': ExchangeNotAvailable,
                      'RATELIMIT': DDoSProtection,
                      'CF_RATELIMIT': DDoSProtection,
                      'INTERNAL_SERVER_ERROR': ExchangeError,
                  },
                  'broad': {
                  },
              },
              'commonCurrencies': {
                  'MIOTA': 'IOTA',  # https://github.com/ccxt/ccxt/issues/7487
              },
          })
  
      def fetch_time(self, params={}):
          response = self.publicGetTime(params)
          #
          #     {
          #         iso: '2020-07-10T05:17:26.716Z',
          #         epoch_millis: 1594358246716,
          #     }
          #
          return self.safe_integer(response, 'epoch_millis')
  
      def fetch_currencies(self, params={}):
          response = self.publicGetCurrencies(params)
          #
          #     [
          #         {
          #             "code":"BEST",
          #             "precision":8
          #         }
          #     ]
          #
          result = {}
          for i in range(0, len(response)):
              currency = response[i]
              id = self.safe_string(currency, 'code')
              code = self.safe_currency_code(id)
              result[code] = {
                  'id': id,
                  'code': code,
                  'name': None,
                  'info': currency,  # the original payload
                  'active': None,
                  'fee': None,
                  'precision': self.safe_integer(currency, 'precision'),
                  'limits': {
                      'amount': {'min': None, 'max': None},
                      'price': {'min': None, 'max': None},
                      'cost': {'min': None, 'max': None},
                      'withdraw': {'min': None, 'max': None},
                  },
              }
          return result
  
      def fetch_markets(self, params={}):
          response = self.publicGetInstruments(params)
          #
          #     [
          #         {
          #             state: 'ACTIVE',
          #             base: {code: 'ETH', precision: 8},
          #             quote: {code: 'CHF', precision: 2},
          #             amount_precision: 4,
          #             market_precision: 2,
          #             min_size: '10.0'
          #         }
          #     ]
          #
          result = []
          for i in range(0, len(response)):
              market = response[i]
              baseAsset = self.safe_value(market, 'base', {})
              quoteAsset = self.safe_value(market, 'quote', {})
              baseId = self.safe_string(baseAsset, 'code')
              quoteId = self.safe_string(quoteAsset, 'code')
              id = baseId + '_' + quoteId
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = base + '/' + quote
              precision = {
                  'amount': self.safe_integer(market, 'amount_precision'),
                  'price': self.safe_integer(market, 'market_precision'),
              }
              limits = {
                  'amount': {
                      'min': None,
                      'max': None,
                  },
                  'price': {
                      'min': None,
                      'max': None,
                  },
                  'cost': {
                      'min': self.safe_float(market, 'min_size'),
                      'max': None,
                  },
              }
              state = self.safe_string(market, 'state')
              active = (state == 'ACTIVE')
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'precision': precision,
                  'limits': limits,
                  'info': market,
                  'active': active,
              })
          return result
  
      def fetch_trading_fees(self, params={}):
          method = self.safe_string(params, 'method')
          params = self.omit(params, 'method')
          if method is None:
              options = self.safe_value(self.options, 'fetchTradingFees', {})
              method = self.safe_string(options, 'method', 'fetchPrivateTradingFees')
          return getattr(self, method)(params)
  
      def fetch_public_trading_fees(self, params={}):
          self.load_markets()
          response = self.publicGetFees(params)
          #
          #     [
          #         {
          #             "fee_group_id":"default",
          #             "display_text":"The standard fee plan.",
          #             "fee_tiers":[
          #                 {"volume":"0.0","fee_group_id":"default","maker_fee":"0.1","taker_fee":"0.15"},
          #                 {"volume":"100.0","fee_group_id":"default","maker_fee":"0.1","taker_fee":"0.13"},
          #                 {"volume":"250.0","fee_group_id":"default","maker_fee":"0.09","taker_fee":"0.13"},
          #                 {"volume":"1000.0","fee_group_id":"default","maker_fee":"0.075","taker_fee":"0.1"},
          #                 {"volume":"5000.0","fee_group_id":"default","maker_fee":"0.06","taker_fee":"0.09"},
          #                 {"volume":"10000.0","fee_group_id":"default","maker_fee":"0.05","taker_fee":"0.075"},
          #                 {"volume":"20000.0","fee_group_id":"default","maker_fee":"0.05","taker_fee":"0.065"}
          #             ],
          #             "fee_discount_rate":"25.0",
          #             "minimum_price_value":"0.12"
          #         }
          #     ]
          #
          feeGroupsById = self.index_by(response, 'fee_group_id')
          feeGroupId = self.safe_value(self.options, 'fee_group_id', 'default')
          feeGroup = self.safe_value(feeGroupsById, feeGroupId, {})
          feeTiers = self.safe_value(feeGroup, 'fee_tiers')
          result = {}
          for i in range(0, len(self.symbols)):
              symbol = self.symbols[i]
              fee = {
                  'info': feeGroup,
                  'symbol': symbol,
                  'maker': None,
                  'taker': None,
                  'percentage': True,
                  'tierBased': True,
              }
              takerFees = []
              makerFees = []
              for i in range(0, len(feeTiers)):
                  tier = feeTiers[i]
                  volume = self.safe_float(tier, 'volume')
                  taker = self.safe_float(tier, 'taker_fee')
                  maker = self.safe_float(tier, 'maker_fee')
                  taker /= 100
                  maker /= 100
                  takerFees.append([volume, taker])
                  makerFees.append([volume, maker])
                  if i == 0:
                      fee['taker'] = taker
                      fee['maker'] = maker
              tiers = {
                  'taker': takerFees,
                  'maker': makerFees,
              }
              fee['tiers'] = tiers
              result[symbol] = fee
          return result
  
      def fetch_private_trading_fees(self, params={}):
          self.load_markets()
          response = self.privateGetAccountFees(params)
          #
          #     {
          #         "account_id": "ed524d00-820a-11e9-8f1e-69602df16d85",
          #         "running_trading_volume": "0.0",
          #         "fee_group_id": "default",
          #         "collect_fees_in_best": False,
          #         "fee_discount_rate": "25.0",
          #         "minimum_price_value": "0.12",
          #         "fee_tiers": [
          #             {"volume": "0.0", "fee_group_id": "default", "maker_fee": "0.1", "taker_fee": "0.1"},
          #             {"volume": "100.0", "fee_group_id": "default", "maker_fee": "0.09", "taker_fee": "0.1"},
          #             {"volume": "250.0", "fee_group_id": "default", "maker_fee": "0.08", "taker_fee": "0.1"},
          #             {"volume": "1000.0", "fee_group_id": "default", "maker_fee": "0.07", "taker_fee": "0.09"},
          #             {"volume": "5000.0", "fee_group_id": "default", "maker_fee": "0.06", "taker_fee": "0.08"},
          #             {"volume": "10000.0", "fee_group_id": "default", "maker_fee": "0.05", "taker_fee": "0.07"},
          #             {"volume": "20000.0", "fee_group_id": "default", "maker_fee": "0.05", "taker_fee": "0.06"},
          #             {"volume": "50000.0", "fee_group_id": "default", "maker_fee": "0.05", "taker_fee": "0.05"}
          #         ],
          #         "active_fee_tier": {"volume": "0.0", "fee_group_id": "default", "maker_fee": "0.1", "taker_fee": "0.1"}
          #     }
          #
          activeFeeTier = self.safe_value(response, 'active_fee_tier', {})
          result = {
              'info': response,
              'maker': self.safe_float(activeFeeTier, 'maker_fee'),
              'taker': self.safe_float(activeFeeTier, 'taker_fee'),
              'percentage': True,
              'tierBased': True,
          }
          feeTiers = self.safe_value(response, 'fee_tiers')
          takerFees = []
          makerFees = []
          for i in range(0, len(feeTiers)):
              tier = feeTiers[i]
              volume = self.safe_float(tier, 'volume')
              taker = self.safe_float(tier, 'taker_fee')
              maker = self.safe_float(tier, 'maker_fee')
              taker /= 100
              maker /= 100
              takerFees.append([volume, taker])
              makerFees.append([volume, maker])
          tiers = {
              'taker': takerFees,
              'maker': makerFees,
          }
          result['tiers'] = tiers
          return result
  
      def parse_ticker(self, ticker, market=None):
          #
          # fetchTicker, fetchTickers
          #
          #     {
          #         "instrument_code":"BTC_EUR",
          #         "sequence":602562,
          #         "time":"2020-07-10T06:27:34.951Z",
          #         "state":"ACTIVE",
          #         "is_frozen":0,
          #         "quote_volume":"1695555.1783768",
          #         "base_volume":"205.67436",
          #         "last_price":"8143.91",
          #         "best_bid":"8143.71",
          #         "best_ask":"8156.9",
          #         "price_change":"-147.47",
          #         "price_change_percentage":"-1.78",
          #         "high":"8337.45",
          #         "low":"8110.0"
          #     }
          #
          timestamp = self.parse8601(self.safe_string(ticker, 'time'))
          marketId = self.safe_string(ticker, 'instrument_code')
          symbol = None
          if marketId is not None:
              if marketId in self.markets_by_id:
                  market = self.markets_by_id[marketId]
              elif marketId is not None:
                  baseId, quoteId = marketId.split('_')
                  base = self.safe_currency_code(baseId)
                  quote = self.safe_currency_code(quoteId)
                  symbol = base + '/' + quote
          if (symbol is None) and (market is not None):
              symbol = market['symbol']
          last = self.safe_float(ticker, 'last_price')
          percentage = self.safe_float(ticker, 'price_change_percentage')
          change = self.safe_float(ticker, 'price_change')
          open = None
          average = None
          if (last is not None) and (change is not None):
              open = last - change
              average = self.sum(last, open) / 2
          baseVolume = self.safe_float(ticker, 'base_volume')
          quoteVolume = self.safe_float(ticker, 'quote_volume')
          vwap = self.vwap(baseVolume, quoteVolume)
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_float(ticker, 'high'),
              'low': self.safe_float(ticker, 'low'),
              'bid': self.safe_float(ticker, 'best_bid'),
              'bidVolume': None,
              'ask': self.safe_float(ticker, 'best_ask'),
              'askVolume': None,
              'vwap': vwap,
              'open': open,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': change,
              'percentage': percentage,
              'average': average,
              'baseVolume': baseVolume,
              'quoteVolume': quoteVolume,
              'info': ticker,
          }
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'instrument_code': market['id'],
          }
          response = self.publicGetMarketTickerInstrumentCode(self.extend(request, params))
          #
          #     {
          #         "instrument_code":"BTC_EUR",
          #         "sequence":602562,
          #         "time":"2020-07-10T06:27:34.951Z",
          #         "state":"ACTIVE",
          #         "is_frozen":0,
          #         "quote_volume":"1695555.1783768",
          #         "base_volume":"205.67436",
          #         "last_price":"8143.91",
          #         "best_bid":"8143.71",
          #         "best_ask":"8156.9",
          #         "price_change":"-147.47",
          #         "price_change_percentage":"-1.78",
          #         "high":"8337.45",
          #         "low":"8110.0"
          #     }
          #
          return self.parse_ticker(response, market)
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          response = self.publicGetMarketTicker(params)
          #
          #     [
          #         {
          #             "instrument_code":"BTC_EUR",
          #             "sequence":602562,
          #             "time":"2020-07-10T06:27:34.951Z",
          #             "state":"ACTIVE",
          #             "is_frozen":0,
          #             "quote_volume":"1695555.1783768",
          #             "base_volume":"205.67436",
          #             "last_price":"8143.91",
          #             "best_bid":"8143.71",
          #             "best_ask":"8156.9",
          #             "price_change":"-147.47",
          #             "price_change_percentage":"-1.78",
          #             "high":"8337.45",
          #             "low":"8110.0"
          #         }
          #     ]
          #
          result = {}
          for i in range(0, len(response)):
              ticker = self.parse_ticker(response[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 = {
              'instrument_code': self.market_id(symbol),
              # level 1 means only the best bid and ask
              # level 2 is a compiled order book up to market precision
              # level 3 is a full orderbook
              # if you wish to get regular updates about orderbooks please use the Websocket channel
              # heavy usage of self endpoint may result in limited access according to rate limits rules
              # 'level': 3,  # default
          }
          if limit is not None:
              request['depth'] = limit
          response = self.publicGetOrderBookInstrumentCode(self.extend(request, params))
          #
          # level 1
          #
          #     {
          #         "instrument_code":"BTC_EUR",
          #         "time":"2020-07-10T07:39:06.343Z",
          #         "asks":{
          #             "value":{
          #                 "price":"8145.29",
          #                 "amount":"0.96538",
          #                 "number_of_orders":1
          #             }
          #         },
          #         "bids":{
          #             "value":{
          #                 "price":"8134.0",
          #                 "amount":"1.5978",
          #                 "number_of_orders":5
          #             }
          #         }
          #     }
          #
          # level 2
          #
          #     {
          #         "instrument_code":"BTC_EUR","time":"2020-07-10T07:36:43.538Z",
          #         "asks":[
          #             {"price":"8146.59","amount":"0.89691","number_of_orders":1},
          #             {"price":"8146.89","amount":"1.92062","number_of_orders":1},
          #             {"price":"8169.5","amount":"0.0663","number_of_orders":1},
          #         ],
          #         "bids":[
          #             {"price":"8143.49","amount":"0.01329","number_of_orders":1},
          #             {"price":"8137.01","amount":"5.34748","number_of_orders":1},
          #             {"price":"8137.0","amount":"2.0","number_of_orders":1},
          #         ]
          #     }
          #
          # level 3
          #
          #     {
          #         "instrument_code":"BTC_EUR",
          #         "time":"2020-07-10T07:32:31.525Z",
          #         "bids":[
          #             {"price":"8146.79","amount":"0.01537","order_id":"5d717da1-a8f4-422d-afcc-03cb6ab66825"},
          #             {"price":"8139.32","amount":"3.66009","order_id":"d0715c68-f28d-4cf1-a450-d56cf650e11c"},
          #             {"price":"8137.51","amount":"2.61049","order_id":"085fd6f4-e835-4ca5-9449-a8f165772e60"},
          #         ],
          #         "asks":[
          #             {"price":"8153.49","amount":"0.93384","order_id":"755d3aa3-42b5-46fa-903d-98f42e9ae6c4"},
          #             {"price":"8153.79","amount":"1.80456","order_id":"62034cf3-b70d-45ff-b285-ba6307941e7c"},
          #             {"price":"8167.9","amount":"0.0018","order_id":"036354e0-71cd-492f-94f2-01f7d4b66422"},
          #         ]
          #     }
          #
          timestamp = self.parse8601(self.safe_string(response, 'time'))
          return self.parse_order_book(response, timestamp, 'bids', 'asks', 'price', 'amount')
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          #     {
          #         "instrument_code":"BTC_EUR",
          #         "granularity":{"unit":"HOURS","period":1},
          #         "high":"9252.65",
          #         "low":"9115.27",
          #         "open":"9250.0",
          #         "close":"9132.35",
          #         "total_amount":"33.85924",
          #         "volume":"311958.9635744",
          #         "time":"2020-05-08T22:59:59.999Z",
          #         "last_sequence":461123
          #     }
          #
          granularity = self.safe_value(ohlcv, 'granularity')
          unit = self.safe_string(granularity, 'unit')
          period = self.safe_string(granularity, 'period')
          units = {
              'MINUTES': 'm',
              'HOURS': 'h',
              'DAYS': 'd',
              'WEEKS': 'w',
              'MONTHS': 'M',
          }
          lowercaseUnit = self.safe_string(units, unit)
          timeframe = period + lowercaseUnit
          durationInSeconds = self.parse_timeframe(timeframe)
          duration = durationInSeconds * 1000
          timestamp = self.parse8601(self.safe_string(ohlcv, 'time'))
          alignedTimestamp = duration * int(timestamp / duration)
          options = self.safe_value(self.options, 'fetchOHLCV', {})
          volumeField = self.safe_string(options, 'volume', 'total_amount')
          return [
              alignedTimestamp,
              self.safe_float(ohlcv, 'open'),
              self.safe_float(ohlcv, 'high'),
              self.safe_float(ohlcv, 'low'),
              self.safe_float(ohlcv, 'close'),
              self.safe_float(ohlcv, volumeField),
          ]
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          periodUnit = self.safe_string(self.timeframes, timeframe)
          period, unit = periodUnit.split('/')
          durationInSeconds = self.parse_timeframe(timeframe)
          duration = durationInSeconds * 1000
          if limit is None:
              limit = 1500
          request = {
              'instrument_code': market['id'],
              # 'from': self.iso8601(since),
              # 'to': self.iso8601(self.milliseconds()),
              'period': period,
              'unit': unit,
          }
          if since is None:
              now = self.milliseconds()
              request['to'] = self.iso8601(now)
              request['from'] = self.iso8601(now - limit * duration)
          else:
              request['from'] = self.iso8601(since)
              request['to'] = self.iso8601(self.sum(since, limit * duration))
          response = self.publicGetCandlesticksInstrumentCode(self.extend(request, params))
          #
          #     [
          #         {"instrument_code":"BTC_EUR","granularity":{"unit":"HOURS","period":1},"high":"9252.65","low":"9115.27","open":"9250.0","close":"9132.35","total_amount":"33.85924","volume":"311958.9635744","time":"2020-05-08T22:59:59.999Z","last_sequence":461123},
          #         {"instrument_code":"BTC_EUR","granularity":{"unit":"HOURS","period":1},"high":"9162.49","low":"9040.0","open":"9132.53","close":"9083.69","total_amount":"26.19685","volume":"238553.7812365","time":"2020-05-08T23:59:59.999Z","last_sequence":461376},
          #         {"instrument_code":"BTC_EUR","granularity":{"unit":"HOURS","period":1},"high":"9135.7","low":"9002.59","open":"9055.45","close":"9133.98","total_amount":"26.21919","volume":"238278.8724959","time":"2020-05-09T00:59:59.999Z","last_sequence":461521},
          #     ]
          #
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      def parse_trade(self, trade, market=None):
          #
          # fetchTrades(public)
          #
          #     {
          #         "instrument_code":"BTC_EUR",
          #         "price":"8137.28",
          #         "amount":"0.22269",
          #         "taker_side":"BUY",
          #         "volume":"1812.0908832",
          #         "time":"2020-07-10T14:44:32.299Z",
          #         "trade_timestamp":1594392272299,
          #         "sequence":603047
          #     }
          #
          # fetchOrder, fetchOpenOrders, fetchClosedOrders trades(private)
          #
          #     {
          #         "fee": {
          #             "fee_amount": "0.0014",
          #             "fee_currency": "BTC",
          #             "fee_percentage": "0.1",
          #             "fee_group_id": "default",
          #             "fee_type": "TAKER",
          #             "running_trading_volume": "0.0"
          #         },
          #         "trade": {
          #             "trade_id": "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
          #             "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
          #             "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
          #             "amount": "1.4",
          #             "side": "BUY",
          #             "instrument_code": "BTC_EUR",
          #             "price": "7341.4",
          #             "time": "2019-09-27T15:05:32.564Z",
          #             "sequence": 48670
          #         }
          #     }
          #
          feeInfo = self.safe_value(trade, 'fee', {})
          trade = self.safe_value(trade, 'trade', trade)
          timestamp = self.parse8601(self.safe_string(trade, 'time'))
          side = self.safe_string_lower_2(trade, 'side', 'taker_side')
          price = self.safe_float(trade, 'price')
          amount = self.safe_float(trade, 'amount')
          cost = self.safe_float(trade, 'volume')
          if (cost is None) and (amount is not None) and (price is not None):
              cost = amount * price
          marketId = self.safe_string(trade, 'instrument_code')
          symbol = None
          if marketId is not None:
              if marketId in self.markets_by_id:
                  market = self.markets_by_id[marketId]
                  symbol = market['symbol']
              else:
                  baseId, quoteId = marketId.split('_')
                  base = self.safe_currency_code(baseId)
                  quote = self.safe_currency_code(quoteId)
                  symbol = base + '/' + quote
          if (market is not None) and (symbol is None):
              symbol = market['symbol']
          feeCost = self.safe_float(feeInfo, 'fee_amount')
          takerOrMaker = None
          fee = None
          if feeCost is not None:
              feeCurrencyId = self.safe_string(feeInfo, 'fee_currency')
              feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
              feeRate = self.safe_float(feeInfo, 'fee_percentage')
              fee = {
                  'cost': feeCost,
                  'currency': feeCurrencyCode,
                  'rate': feeRate,
              }
              takerOrMaker = self.safe_string_lower(feeInfo, 'fee_type')
          return {
              'id': self.safe_string_2(trade, 'trade_id', 'sequence'),
              'order': self.safe_string(trade, 'order_id'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'type': None,
              '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 = {
              'instrument_code': market['id'],
              # 'from': self.iso8601(since),
              # 'to': self.iso8601(self.milliseconds()),
          }
          if since is not None:
              # returns price ticks for a specific market with an interval of maximum of 4 hours
              # sorted by latest first
              request['from'] = self.iso8601(since)
              request['to'] = self.iso8601(self.sum(since, 14400000))
          response = self.publicGetPriceTicksInstrumentCode(self.extend(request, params))
          #
          #     [
          #         {
          #             "instrument_code":"BTC_EUR",
          #             "price":"8137.28",
          #             "amount":"0.22269",
          #             "taker_side":"BUY",
          #             "volume":"1812.0908832",
          #             "time":"2020-07-10T14:44:32.299Z",
          #             "trade_timestamp":1594392272299,
          #             "sequence":603047
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def fetch_balance(self, params={}):
          self.load_markets()
          response = self.privateGetAccountBalances(params)
          #
          #     {
          #         "account_id":"4b95934f-55f1-460c-a525-bd5afc0cf071",
          #         "balances":[
          #             {
          #                 "account_id":"4b95934f-55f1-460c-a525-bd5afc0cf071",
          #                 "currency_code":"BTC",
          #                 "change":"10.0",
          #                 "available":"10.0",
          #                 "locked":"0.0",
          #                 "sequence":142135994,
          #                 "time":"2020-07-01T10:57:32.959Z"
          #             }
          #         ]
          #     }
          #
          balances = self.safe_value(response, 'balances', [])
          result = {'info': response}
          for i in range(0, len(balances)):
              balance = balances[i]
              currencyId = self.safe_string(balance, 'currency_code')
              code = self.safe_currency_code(currencyId)
              account = self.account()
              account['free'] = self.safe_float(balance, 'available')
              account['used'] = self.safe_float(balance, 'locked')
              result[code] = account
          return self.parse_balance(result)
  
      def parse_deposit_address(self, depositAddress, currency=None):
          code = None
          if currency is not None:
              code = currency['code']
          address = self.safe_string(depositAddress, 'address')
          tag = self.safe_string(depositAddress, 'destination_tag')
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'tag': tag,
              'info': depositAddress,
          }
  
      def create_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'currency': currency['id'],
          }
          response = self.privatePostAccountDepositCrypto(self.extend(request, params))
          #
          #     {
          #         "address":"rBnNhk95FrdNisZtXcStzriFS8vEzz53DM",
          #         "destination_tag":"865690307",
          #         "enabled":true,
          #         "is_smart_contract":false
          #     }
          #
          return self.parse_deposit_address(response, currency)
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'currency_code': currency['id'],
          }
          response = self.privateGetAccountDepositCryptoCurrencyCode(self.extend(request, params))
          #
          #     {
          #         "address":"rBnNhk95FrdNisZtXcStzriFS8vEzz53DM",
          #         "destination_tag":"865690307",
          #         "enabled":true,
          #         "is_smart_contract":false,
          #         "can_create_more":false
          #     }
          #
          return self.parse_deposit_address(response, currency)
  
      def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              # 'cursor': 'string',  # pointer specifying the position from which the next pages should be returned
          }
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['currency_code'] = currency['id']
          if limit is not None:
              request['max_page_size'] = limit
          if since is not None:
              to = self.safe_string(params, 'to')
              if to is None:
                  raise ArgumentsRequired(self.id + ' fetchDeposits requires a "to" iso8601 string param with the since argument is specified')
              request['from'] = self.iso8601(since)
          response = self.privateGetAccountDeposits(self.extend(request, params))
          #
          #     {
          #         "deposit_history": [
          #             {
          #                 "transaction_id": "e5342efcd-d5b7-4a56-8e12-b69ffd68c5ef",
          #                 "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
          #                 "amount": "100",
          #                 "type": "CRYPTO",
          #                 "funds_source": "INTERNAL",
          #                 "time": "2020-04-22T09:57:47Z",
          #                 "currency": "BTC",
          #                 "fee_amount": "0.0",
          #                 "fee_currency": "BTC"
          #             },
          #             {
          #                 "transaction_id": "79793d00-2899-4a4d-95b7-73ae6b31384f",
          #                 "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
          #                 "time": "2020-05-05T11:22:07.925Z",
          #                 "currency": "EUR",
          #                 "funds_source": "EXTERNAL",
          #                 "type": "FIAT",
          #                 "amount": "50.0",
          #                 "fee_amount": "0.01",
          #                 "fee_currency": "EUR"
          #             }
          #         ],
          #         "max_page_size": 2,
          #         "cursor": "eyJhY2NvdW50X2lkIjp7InMiOiJlMzY5YWM4MC00NTc3LTExZTktYWUwOC05YmVkYzQ3OTBiODQiLCJzcyI6W10sIm5zIjpbXSwiYnMiOltdLCJtIjp7fSwibCI6W119LCJpdGVtX2tleSI6eyJzIjoiV0lUSERSQVdBTDo6MmFlMjYwY2ItOTk3MC00YmNiLTgxNmEtZGY4MDVmY2VhZTY1Iiwic3MiOltdLCJucyI6W10sImJzIjpbXSwibSI6e30sImwiOltdfSwiZ2xvYmFsX3dpdGhkcmF3YWxfaW5kZXhfaGFzaF9rZXkiOnsicyI6ImUzNjlhYzgwLTQ1NzctMTFlOS1hZTA4LTliZWRjNDc5MGI4NCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX0sInRpbWVzdGFtcCI6eyJuIjoiMTU4ODA1ODc2Nzk0OCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX19"
          #     }
          #
          depositHistory = self.safe_value(response, 'deposit_history', [])
          return self.parse_transactions(depositHistory, currency, since, limit, {'type': 'deposit'})
  
      def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              # 'cursor': 'string',  # pointer specifying the position from which the next pages should be returned
          }
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['currency_code'] = currency['id']
          if limit is not None:
              request['max_page_size'] = limit
          if since is not None:
              to = self.safe_string(params, 'to')
              if to is None:
                  raise ArgumentsRequired(self.id + ' fetchWithdrawals requires a "to" iso8601 string param with the since argument is specified')
              request['from'] = self.iso8601(since)
          response = self.privateGetAccountWithdrawals(self.extend(request, params))
          #
          #     {
          #         "withdrawal_history": [
          #             {
          #                 "account_id": "e369ac80-4577-11e9-ae08-9bedc4790b84",
          #                 "amount": "0.1",
          #                 "currency": "BTC",
          #                 "fee_amount": "0.00002",
          #                 "fee_currency": "BTC",
          #                 "funds_source": "EXTERNAL",
          #                 "related_transaction_id": "e298341a-3855-405e-bce3-92db368a3157",
          #                 "time": "2020-05-05T11:11:32.110Z",
          #                 "transaction_id": "6693ff40-bb10-4dcf-ada7-3b287727c882",
          #                 "type": "CRYPTO"
          #             },
          #             {
          #                 "account_id": "e369ac80-4577-11e9-ae08-9bedc4790b84",
          #                 "amount": "0.1",
          #                 "currency": "BTC",
          #                 "fee_amount": "0.0",
          #                 "fee_currency": "BTC",
          #                 "funds_source": "INTERNAL",
          #                 "time": "2020-05-05T10:29:53.464Z",
          #                 "transaction_id": "ec9703b1-954b-4f76-adea-faac66eabc0b",
          #                 "type": "CRYPTO"
          #             }
          #         ],
          #         "cursor": "eyJhY2NvdW50X2lkIjp7InMiOiJlMzY5YWM4MC00NTc3LTExZTktYWUwOC05YmVkYzQ3OTBiODQiLCJzcyI6W10sIm5zIjpbXSwiYnMiOltdLCJtIjp7fSwibCI6W119LCJpdGVtX2tleSI6eyJzIjoiV0lUSERSQVdBTDo6ZWM5NzAzYjEtOTU0Yi00Zjc2LWFkZWEtZmFhYzY2ZWFiYzBiIiwic3MiOltdLCJucyI6W10sImJzIjpbXSwibSI6e30sImwiOltdfSwiZ2xvYmFsX3dpdGhkcmF3YWxfaW5kZXhfaGFzaF9rZXkiOnsicyI6ImUzNjlhYzgwLTQ1NzctMTFlOS1hZTA4LTliZWRjNDc5MGI4NCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX0sInRpbWVzdGFtcCI6eyJuIjoiMTU4ODY3NDU5MzQ2NCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX19",
          #         "max_page_size": 2
          #     }
          #
          withdrawalHistory = self.safe_value(response, 'withdrawal_history', [])
          return self.parse_transactions(withdrawalHistory, currency, since, limit, {'type': 'withdrawal'})
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchDeposits, fetchWithdrawals
          #
          #     {
          #         "transaction_id": "C2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
          #         "type": "FIAT",
          #         "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
          #         "amount": "1234.5678",
          #         "time": "2019-08-24T14:15:22Z",
          #         "funds_source": "INTERNAL",
          #         "currency": "BTC",
          #         "fee_amount": "1234.5678",
          #         "fee_currency": "BTC",
          #         "blockchain_transaction_id": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
          #         "related_transaction_id": "e298341a-3855-405e-bce3-92db368a3157"
          #     }
          #
          id = self.safe_string(transaction, 'transaction_id')
          amount = self.safe_float(transaction, 'amount')
          timestamp = self.parse8601(self.safe_string(transaction, 'time'))
          currencyId = self.safe_string(transaction, 'currency')
          code = self.safe_currency_code(currencyId, currency)
          status = None
          feeCost = self.safe_float(transaction, 'fee_amount')
          fee = None
          if feeCost is not None:
              feeCurrencyId = self.safe_string(transaction, 'fee_currency')
              feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
              fee = {
                  'cost': feeCost,
                  'currency': feeCurrencyCode,
              }
          return {
              'info': transaction,
              'id': id,
              'currency': code,
              'amount': amount,
              'address': None,
              'addressFrom': None,
              'addressTo': None,
              'tag': None,
              'tagFrom': None,
              'tagTo': None,
              'status': status,
              'type': None,
              'updated': None,
              'txid': self.safe_string(transaction, 'blockchain_transaction_id'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'fee': fee,
          }
  
      def parse_order_status(self, status):
          statuses = {
              'FILLED': 'open',
              'FILLED_FULLY': 'closed',
              'FILLED_CLOSED': 'canceled',
              'FILLED_REJECTED': 'rejected',
              'OPEN': 'open',
              'REJECTED': 'rejected',
              'CLOSED': 'canceled',
              'FAILED': 'failed',
              'STOP_TRIGGERED': 'triggered',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_order(self, order, market=None):
          #
          # createOrder
          #
          #     {
          #         "order_id": "d5492c24-2995-4c18-993a-5b8bf8fffc0d",
          #         "client_id": "d75fb03b-b599-49e9-b926-3f0b6d103206",
          #         "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
          #         "instrument_code": "BTC_EUR",
          #         "time": "2019-08-01T08:00:44.026Z",
          #         "side": "BUY",
          #         "price": "5000",
          #         "amount": "1",
          #         "filled_amount": "0.5",
          #         "type": "LIMIT",
          #         "time_in_force": "GOOD_TILL_CANCELLED"
          #     }
          #
          # fetchOrder, fetchOpenOrders, fetchClosedOrders
          #
          #     {
          #         "order": {
          #             "order_id": "66756a10-3e86-48f4-9678-b634c4b135b2",
          #             "account_id": "1eb2ad5d-55f1-40b5-bc92-7dc05869e905",
          #             "instrument_code": "BTC_EUR",
          #             "amount": "1234.5678",
          #             "filled_amount": "1234.5678",
          #             "side": "BUY",
          #             "type": "LIMIT",
          #             "status": "OPEN",
          #             "sequence": 123456789,
          #             "price": "1234.5678",
          #             "average_price": "1234.5678",
          #             "reason": "INSUFFICIENT_FUNDS",
          #             "time": "2019-08-24T14:15:22Z",
          #             "time_in_force": "GOOD_TILL_CANCELLED",
          #             "time_last_updated": "2019-08-24T14:15:22Z",
          #             "expire_after": "2019-08-24T14:15:22Z",
          #             "is_post_only": False,
          #             "time_triggered": "2019-08-24T14:15:22Z",
          #             "trigger_price": "1234.5678"
          #         },
          #         "trades": [
          #             {
          #                 "fee": {
          #                     "fee_amount": "0.0014",
          #                     "fee_currency": "BTC",
          #                     "fee_percentage": "0.1",
          #                     "fee_group_id": "default",
          #                     "fee_type": "TAKER",
          #                     "running_trading_volume": "0.0"
          #                 },
          #                 "trade": {
          #                     "trade_id": "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
          #                     "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
          #                     "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
          #                     "amount": "1.4",
          #                     "side": "BUY",
          #                     "instrument_code": "BTC_EUR",
          #                     "price": "7341.4",
          #                     "time": "2019-09-27T15:05:32.564Z",
          #                     "sequence": 48670
          #                 }
          #             }
          #         ]
          #     }
          #
          rawTrades = self.safe_value(order, 'trades', [])
          order = self.safe_value(order, 'order', order)
          id = self.safe_string(order, 'order_id')
          clientOrderId = self.safe_string(order, 'client_id')
          timestamp = self.parse8601(self.safe_string(order, 'time'))
          status = self.parse_order_status(self.safe_string(order, 'status'))
          symbol = None
          marketId = self.safe_string(order, 'instrument_code')
          if marketId is not None:
              if marketId in self.markets_by_id:
                  market = self.markets_by_id[marketId]
              else:
                  baseId, quoteId = marketId.split('_')
                  base = self.safe_currency_code(baseId)
                  quote = self.safe_currency_code(quoteId)
                  symbol = base + '/' + quote
          if (symbol is None) and (market is not None):
              symbol = market['symbol']
          price = self.safe_float(order, 'price')
          amount = self.safe_float(order, 'amount')
          cost = None
          filled = self.safe_float(order, 'filled_amount')
          remaining = None
          if filled is not None:
              if amount is not None:
                  remaining = max(0, amount - filled)
                  if status is None:
                      if remaining > 0:
                          status = 'open'
                      else:
                          status = 'closed'
          side = self.safe_string_lower(order, 'side')
          type = self.safe_string_lower(order, 'type')
          trades = self.parse_trades(rawTrades, market, None, None)
          fees = []
          numTrades = len(trades)
          lastTradeTimestamp = None
          tradeCost = None
          tradeAmount = None
          if numTrades > 0:
              lastTradeTimestamp = trades[0]['timestamp']
              tradeCost = 0
              tradeAmount = 0
              for i in range(0, len(trades)):
                  trade = trades[i]
                  fees.append(trade['fee'])
                  lastTradeTimestamp = max(lastTradeTimestamp, trade['timestamp'])
                  tradeCost = self.sum(tradeCost, trade['cost'])
                  tradeAmount = self.sum(tradeAmount, trade['amount'])
          average = self.safe_float(order, 'average_price')
          if average is None:
              if (tradeCost is not None) and (tradeAmount is not None) and (tradeAmount != 0):
                  average = tradeCost / tradeAmount
          if cost is None:
              if (average is not None) and (filled is not None):
                  cost = average * filled
          result = {
              'id': id,
              'clientOrderId': clientOrderId,
              'info': order,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': lastTradeTimestamp,
              'symbol': symbol,
              'type': type,
              'side': side,
              'price': price,
              'amount': amount,
              'cost': cost,
              'average': average,
              'filled': filled,
              'remaining': remaining,
              'status': status,
              # 'fee': None,
              'trades': trades,
          }
          numFees = len(fees)
          if numFees > 0:
              if numFees == 1:
                  result['fee'] = fees[0]
              else:
                  feesByCurrency = self.group_by(fees, 'currency')
                  feeCurrencies = list(feesByCurrency.keys())
                  numFeesByCurrency = len(feeCurrencies)
                  if numFeesByCurrency == 1:
                      feeCurrency = feeCurrencies[0]
                      feeArray = self.safe_value(feesByCurrency, feeCurrency)
                      feeCost = 0
                      for i in range(0, len(feeArray)):
                          feeCost = self.sum(feeCost, feeArray[i]['cost'])
                      result['fee'] = {
                          'cost': feeCost,
                          'currency': feeCurrency,
                      }
                  else:
                      result['fees'] = fees
          else:
              result['fee'] = None
          return result
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          uppercaseType = type.upper()
          request = {
              'instrument_code': market['id'],
              'type': type.upper(),  # LIMIT, MARKET, STOP
              'side': side.upper(),  # or SELL
              'amount': self.amount_to_precision(symbol, amount),
              # "price": "1234.5678",  # required for LIMIT and STOP orders
              # "client_id": "d75fb03b-b599-49e9-b926-3f0b6d103206",  # optional
              # "time_in_force": "GOOD_TILL_CANCELLED",  # limit orders only, GOOD_TILL_CANCELLED, GOOD_TILL_TIME, IMMEDIATE_OR_CANCELLED and FILL_OR_KILL
              # "expire_after": "2020-07-02T19:40:13Z",  # required for GOOD_TILL_TIME
              # "is_post_only": False,  # limit orders only, optional
              # "trigger_price": "1234.5678"  # required for stop orders
          }
          priceIsRequired = False
          if uppercaseType == 'LIMIT' or uppercaseType == 'STOP':
              priceIsRequired = True
          if uppercaseType == 'STOP':
              triggerPrice = self.safe_float(params, 'trigger_price')
              if triggerPrice is None:
                  raise ArgumentsRequired(self.id + ' createOrder requires a trigger_price param for ' + type + ' orders')
              request['trigger_price'] = self.price_to_precision(symbol, triggerPrice)
              params = self.omit(params, 'trigger_price')
          if priceIsRequired:
              request['price'] = self.price_to_precision(symbol, price)
          clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_id')
          if clientOrderId is not None:
              request['client_id'] = clientOrderId
              params = self.omit(params, ['clientOrderId', 'client_id'])
          response = self.privatePostAccountOrders(self.extend(request, params))
          #
          #     {
          #         "order_id": "d5492c24-2995-4c18-993a-5b8bf8fffc0d",
          #         "client_id": "d75fb03b-b599-49e9-b926-3f0b6d103206",
          #         "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
          #         "instrument_code": "BTC_EUR",
          #         "time": "2019-08-01T08:00:44.026Z",
          #         "side": "BUY",
          #         "price": "5000",
          #         "amount": "1",
          #         "filled_amount": "0.5",
          #         "type": "LIMIT",
          #         "time_in_force": "GOOD_TILL_CANCELLED"
          #     }
          #
          return self.parse_order(response, market)
  
      def cancel_order(self, id, symbol=None, params={}):
          self.load_markets()
          clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_id')
          params = self.omit(params, ['clientOrderId', 'client_id'])
          method = 'privateDeleteAccountOrdersOrderId'
          request = {}
          if clientOrderId is not None:
              method = 'privateDeleteAccountOrdersClientClientId'
              request['client_id'] = clientOrderId
          else:
              request['order_id'] = id
          response = getattr(self, method)(self.extend(request, params))
          #
          # responds with an empty body
          #
          return response
  
      def cancel_all_orders(self, symbol=None, params={}):
          self.load_markets()
          request = {}
          if symbol is not None:
              market = self.market(symbol)
              request['instrument_code'] = market['id']
          response = self.privateDeleteAccountOrders(self.extend(request, params))
          #
          #     [
          #         "a10e9bd1-8f72-4cfe-9f1b-7f1c8a9bd8ee"
          #     ]
          #
          return response
  
      def cancel_orders(self, ids, symbol=None, params={}):
          self.load_markets()
          request = {
              'ids': ','.join(ids),
          }
          response = self.privateDeleteAccountOrders(self.extend(request, params))
          #
          #     [
          #         "a10e9bd1-8f72-4cfe-9f1b-7f1c8a9bd8ee"
          #     ]
          #
          return response
  
      def fetch_order(self, id, symbol=None, params={}):
          self.load_markets()
          request = {
              'order_id': id,
          }
          response = self.privateGetAccountOrdersOrderId(self.extend(request, params))
          #
          #     {
          #         "order": {
          #             "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
          #             "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
          #             "time_last_updated": "2019-09-27T15:05:35.096Z",
          #             "sequence": 48782,
          #             "price": "7349.2",
          #             "filled_amount": "100.0",
          #             "status": "FILLED_FULLY",
          #             "amount": "100.0",
          #             "instrument_code": "BTC_EUR",
          #             "side": "BUY",
          #             "time": "2019-09-27T15:05:32.063Z",
          #             "type": "MARKET"
          #         },
          #         "trades": [
          #             {
          #                 "fee": {
          #                     "fee_amount": "0.0014",
          #                     "fee_currency": "BTC",
          #                     "fee_percentage": "0.1",
          #                     "fee_group_id": "default",
          #                     "fee_type": "TAKER",
          #                     "running_trading_volume": "0.0"
          #                 },
          #                 "trade": {
          #                     "trade_id": "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
          #                     "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
          #                     "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
          #                     "amount": "1.4",
          #                     "side": "BUY",
          #                     "instrument_code": "BTC_EUR",
          #                     "price": "7341.4",
          #                     "time": "2019-09-27T15:05:32.564Z",
          #                     "sequence": 48670
          #                 }
          #             }
          #         ]
          #     }
          #
          return self.parse_order(response)
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              # 'from': self.iso8601(since),
              # 'to': self.iso8601(self.milliseconds()),  # max range is 100 days
              # 'instrument_code': market['id'],
              # 'with_cancelled_and_rejected': False,  # default is False, orders which have been cancelled by the user before being filled or rejected by the system as invalid, additionally, all inactive filled orders which would return with "with_just_filled_inactive"
              # 'with_just_filled_inactive': False,  # orders which have been filled and are no longer open, use of "with_cancelled_and_rejected" extends "with_just_filled_inactive" and in case both are specified the latter is ignored
              # 'with_just_orders': False,  # do not return any trades corresponsing to the orders, it may be significanly faster and should be used if user is not interesting in trade information
              # 'max_page_size': 100,
              # 'cursor': 'string',  # pointer specifying the position from which the next pages should be returned
          }
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['instrument_code'] = market['id']
          if since is not None:
              to = self.safe_string(params, 'to')
              if to is None:
                  raise ArgumentsRequired(self.id + ' fetchOrders requires a "to" iso8601 string param with the since argument is specified, max range is 100 days')
              request['from'] = self.iso8601(since)
          if limit is not None:
              request['max_page_size'] = limit
          response = self.privateGetAccountOrders(self.extend(request, params))
          #
          #     {
          #         "order_history": [
          #             {
          #                 "order": {
          #                     "trigger_price": "12089.88",
          #                     "order_id": "d453ca12-c650-46dd-9dee-66910d96bfc0",
          #                     "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
          #                     "instrument_code": "BTC_USDT",
          #                     "time": "2019-08-23T10:02:31.663Z",
          #                     "side": "SELL",
          #                     "price": "10159.76",
          #                     "average_price": "10159.76",
          #                     "amount": "0.2",
          #                     "filled_amount": "0.2",
          #                     "type": "STOP",
          #                     "sequence": 8,
          #                     "status": "FILLED_FULLY"
          #                 },
          #                 "trades": [
          #                     {
          #                         "fee": {
          #                             "fee_amount": "0.4188869",
          #                             "fee_currency": "USDT",
          #                             "fee_percentage": "0.1",
          #                             "fee_group_id": "default",
          #                             "fee_type": "TAKER",
          #                             "running_trading_volume": "0.0"
          #                         },
          #                         "trade": {
          #                             "trade_id": "ec82896f-fd1b-4cbb-89df-a9da85ccbb4b",
          #                             "order_id": "d453ca12-c650-46dd-9dee-66910d96bfc0",
          #                             "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
          #                             "amount": "0.2",
          #                             "side": "SELL",
          #                             "instrument_code": "BTC_USDT",
          #                             "price": "10159.76",
          #                             "time": "2019-08-23T10:02:32.663Z",
          #                             "sequence": 9
          #                         }
          #                     }
          #                 ]
          #             },
          #             {
          #                 "order": {
          #                     "order_id": "5151a99e-f414-418f-8cf1-2568d0a63ea5",
          #                     "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
          #                     "instrument_code": "BTC_USDT",
          #                     "time": "2019-08-23T10:01:36.773Z",
          #                     "side": "SELL",
          #                     "price": "12289.88",
          #                     "amount": "0.5",
          #                     "filled_amount": "0.0",
          #                     "type": "LIMIT",
          #                     "sequence": 7,
          #                     "status": "OPEN"
          #                 },
          #                 "trades": []
          #             },
          #             {
          #                 "order": {
          #                     "order_id": "ac80d857-75e1-4733-9070-fd4288395fdc",
          #                     "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
          #                     "instrument_code": "BTC_USDT",
          #                     "time": "2019-08-23T10:01:25.031Z",
          #                     "side": "SELL",
          #                     "price": "11089.88",
          #                     "amount": "0.1",
          #                     "filled_amount": "0.0",
          #                     "type": "LIMIT",
          #                     "sequence": 6,
          #                     "status": "OPEN"
          #                 },
          #                 "trades": []
          #             }
          #         ],
          #         "max_page_size": 100
          #     }
          #
          orderHistory = self.safe_value(response, 'order_history', [])
          return self.parse_orders(orderHistory, market, since, limit)
  
      def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          request = {
              'with_cancelled_and_rejected': True,  # default is False, orders which have been cancelled by the user before being filled or rejected by the system as invalid, additionally, all inactive filled orders which would return with "with_just_filled_inactive"
          }
          return self.fetch_open_orders(symbol, since, limit, self.extend(request, params))
  
      def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              'order_id': id,
              # 'max_page_size': 100,
              # 'cursor': 'string',  # pointer specifying the position from which the next pages should be returned
          }
          if limit is not None:
              request['max_page_size'] = limit
          response = self.privateGetAccountOrdersOrderIdTrades(self.extend(request, params))
          #
          #     {
          #         "trade_history": [
          #             {
          #                 "trade": {
          #                     "trade_id": "2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
          #                     "order_id": "66756a10-3e86-48f4-9678-b634c4b135b2",
          #                     "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
          #                     "amount": "1234.5678",
          #                     "side": "BUY",
          #                     "instrument_code": "BTC_EUR",
          #                     "price": "1234.5678",
          #                     "time": "2019-08-24T14:15:22Z",
          #                     "price_tick_sequence": 0,
          #                     "sequence": 123456789
          #                 },
          #                 "fee": {
          #                     "fee_amount": "1234.5678",
          #                     "fee_percentage": "1234.5678",
          #                     "fee_group_id": "default",
          #                     "running_trading_volume": "1234.5678",
          #                     "fee_currency": "BTC",
          #                     "fee_type": "TAKER"
          #                 }
          #             }
          #         ],
          #         "max_page_size": 0,
          #         "cursor": "string"
          #     }
          #
          tradeHistory = self.safe_value(response, 'trade_history', [])
          market = None
          if symbol is not None:
              market = self.market(symbol)
          return self.parse_trades(tradeHistory, market, since, limit)
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              # 'from': self.iso8601(since),
              # 'to': self.iso8601(self.milliseconds()),  # max range is 100 days
              # 'instrument_code': market['id'],
              # 'max_page_size': 100,
              # 'cursor': 'string',  # pointer specifying the position from which the next pages should be returned
          }
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['instrument_code'] = market['id']
          if since is not None:
              to = self.safe_string(params, 'to')
              if to is None:
                  raise ArgumentsRequired(self.id + ' fetchMyTrades requires a "to" iso8601 string param with the since argument is specified, max range is 100 days')
              request['from'] = self.iso8601(since)
          if limit is not None:
              request['max_page_size'] = limit
          response = self.privateGetAccountTrades(self.extend(request, params))
          #
          #     {
          #         "trade_history": [
          #             {
          #                 "trade": {
          #                     "trade_id": "2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
          #                     "order_id": "66756a10-3e86-48f4-9678-b634c4b135b2",
          #                     "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
          #                     "amount": "1234.5678",
          #                     "side": "BUY",
          #                     "instrument_code": "BTC_EUR",
          #                     "price": "1234.5678",
          #                     "time": "2019-08-24T14:15:22Z",
          #                     "price_tick_sequence": 0,
          #                     "sequence": 123456789
          #                 },
          #                 "fee": {
          #                     "fee_amount": "1234.5678",
          #                     "fee_percentage": "1234.5678",
          #                     "fee_group_id": "default",
          #                     "running_trading_volume": "1234.5678",
          #                     "fee_currency": "BTC",
          #                     "fee_type": "TAKER"
          #                 }
          #             }
          #         ],
          #         "max_page_size": 0,
          #         "cursor": "string"
          #     }
          #
          tradeHistory = self.safe_value(response, 'trade_history', [])
          return self.parse_trades(tradeHistory, market, since, limit)
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          url = self.urls['api'][api] + '/' + self.version + '/' + self.implode_params(path, params)
          query = self.omit(params, self.extract_params(path))
          if api == 'public':
              if query:
                  url += '?' + self.urlencode(query)
          elif api == 'private':
              self.check_required_credentials()
              headers = {
                  'Accept': 'application/json',
                  'Authorization': 'Bearer ' + self.apiKey,
              }
              if method == 'POST':
                  body = self.json(query)
                  headers['Content-Type'] = 'application/json'
              else:
                  if query:
                      url += '?' + self.urlencode(query)
          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":"MISSING_FROM_PARAM"}
          #     {"error":"MISSING_TO_PARAM"}
          #     {"error":"CANDLESTICKS_TIME_RANGE_TOO_BIG"}
          #
          feedback = self.id + ' ' + body
          message = self.safe_string(response, 'error')
          if message is not None:
              self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
              self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
              raise ExchangeError(feedback)  # unknown message
  