text: # -*- coding: utf-8 -*-
  
  # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
  
  from ccxt.base.exchange import Exchange
  
  # -----------------------------------------------------------------------------
  
  try:
      basestring  # Python 3
  except NameError:
      basestring = str  # Python 2
  import hashlib
  import math
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import PermissionDenied
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import BadSymbol
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import AddressPending
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import DDoSProtection
  from ccxt.base.errors import ExchangeNotAvailable
  from ccxt.base.errors import OnMaintenance
  from ccxt.base.decimal_to_precision import TRUNCATE
  from ccxt.base.decimal_to_precision import DECIMAL_PLACES
  
  
  class bittrex(Exchange):
  
      def describe(self):
          return self.deep_extend(super(bittrex, self).describe(), {
              'id': 'bittrex',
              'name': 'Bittrex',
              'countries': ['US'],
              'version': 'v3',
              'rateLimit': 1500,
              'certified': True,
              'pro': True,
              # new metainfo interface
              'has': {
                  'CORS': False,
                  'cancelAllOrders': True,
                  'cancelOrder': True,
                  'createMarketOrder': True,
                  'createOrder': True,
                  'fetchBalance': True,
                  'fetchDeposits': True,
                  'fetchDepositAddress': True,
                  'fetchClosedOrders': True,
                  'fetchCurrencies': True,
                  'fetchMarkets': True,
                  'fetchMyTrades': 'emulated',
                  'fetchOHLCV': True,
                  'fetchOrder': True,
                  'fetchOrderTrades': True,
                  'fetchOrderBook': True,
                  'fetchOpenOrders': True,
                  'fetchTicker': True,
                  'fetchTickers': True,
                  'fetchTime': True,
                  'fetchTrades': True,
                  'fetchTransactions': False,
                  'fetchWithdrawals': True,
                  'withdraw': True,
              },
              'timeframes': {
                  '1m': 'MINUTE_1',
                  '5m': 'MINUTE_5',
                  '1h': 'HOUR_1',
                  '1d': 'DAY_1',
              },
              'hostname': 'bittrex.com',
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/51840849/87153921-edf53180-c2c0-11ea-96b9-f2a9a95a455b.jpg',
                  'api': {
                      'public': 'https://api.bittrex.com',
                      'private': 'https://api.bittrex.com',
                  },
                  'www': 'https://bittrex.com',
                  'doc': [
                      'https://bittrex.github.io/api/v3',
                  ],
                  'fees': [
                      'https://bittrex.zendesk.com/hc/en-us/articles/115003684371-BITTREX-SERVICE-FEES-AND-WITHDRAWAL-LIMITATIONS',
                      'https://bittrex.zendesk.com/hc/en-us/articles/115000199651-What-fees-does-Bittrex-charge-',
                  ],
                  'referral': 'https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B',
              },
              'api': {
                  'public': {
                      'get': [
                          'ping',
                          'currencies',
                          'currencies/{symbol}',
                          'markets',
                          'markets/tickers',
                          'markets/summaries',
                          'markets/{marketSymbol}',
                          'markets/{marketSymbol}/summary',
                          'markets/{marketSymbol}/orderbook',
                          'markets/{marketSymbol}/trades',
                          'markets/{marketSymbol}/ticker',
                          'markets/{marketSymbol}/candles/{candleInterval}/recent',
                          'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}/{month}/{day}',
                          'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}/{month}',
                          'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}',
                      ],
                  },
                  'private': {
                      'get': [
                          'account',
                          'account/volume',
                          'addresses',
                          'addresses/{currencySymbol}',
                          'balances',
                          'balances/{currencySymbol}',
                          'deposits/open',
                          'deposits/closed',
                          'deposits/ByTxId/{txId}',
                          'deposits/{depositId}',
                          'orders/closed',
                          'orders/open',
                          'orders/{orderId}',
                          'orders/{orderId}/executions',
                          'ping',
                          'subaccounts/{subaccountId}',
                          'subaccounts',
                          'withdrawals/open',
                          'withdrawals/closed',
                          'withdrawals/ByTxId/{txId}',
                          'withdrawals/{withdrawalId}',
                          'withdrawals/whitelistAddresses',
                          'conditional-orders/{conditionalOrderId}',
                          'conditional-orders/closed',
                          'conditional-orders/open',
                          'transfers/sent',
                          'transfers/received',
                          'transfers/{transferId}',
                      ],
                      'post': [
                          'addresses',
                          'orders',
                          'subaccounts',
                          'withdrawals',
                          'conditional-orders',
                          'transfers',
                      ],
                      'delete': [
                          'orders/open',
                          'orders/{orderId}',
                          'withdrawals/{withdrawalId}',
                          'conditional-orders/{conditionalOrderId}',
                      ],
                  },
              },
              'fees': {
                  'trading': {
                      'tierBased': False,
                      'percentage': True,
                      'maker': 0.0025,
                      'taker': 0.0025,
                  },
                  'funding': {
                      'tierBased': False,
                      'percentage': False,
                      'withdraw': {
                          'BTC': 0.0005,
                          'LTC': 0.01,
                          'DOGE': 2,
                          'VTC': 0.02,
                          'PPC': 0.02,
                          'FTC': 0.2,
                          'RDD': 2,
                          'NXT': 2,
                          'DASH': 0.05,
                          'POT': 0.002,
                          'BLK': 0.02,
                          'EMC2': 0.2,
                          'XMY': 0.2,
                          'GLD': 0.0002,
                          'SLR': 0.2,
                          'GRS': 0.2,
                      },
                      'deposit': {
                          'BTC': 0,
                          'LTC': 0,
                          'DOGE': 0,
                          'VTC': 0,
                          'PPC': 0,
                          'FTC': 0,
                          'RDD': 0,
                          'NXT': 0,
                          'DASH': 0,
                          'POT': 0,
                          'BLK': 0,
                          'EMC2': 0,
                          'XMY': 0,
                          'GLD': 0,
                          'SLR': 0,
                          'GRS': 0,
                      },
                  },
              },
              'exceptions': {
                  'exact': {
                      'BAD_REQUEST': BadRequest,  # {"code":"BAD_REQUEST","detail":"Refer to the data field for specific field validation failures.","data":{"invalidRequestParameter":"day"}}
                      'STARTDATE_OUT_OF_RANGE': BadRequest,  # {"code":"STARTDATE_OUT_OF_RANGE"}
                      # 'Call to Cancel was throttled. Try again in 60 seconds.': DDoSProtection,
                      # 'Call to GetBalances was throttled. Try again in 60 seconds.': DDoSProtection,
                      'APISIGN_NOT_PROVIDED': AuthenticationError,
                      'INVALID_SIGNATURE': AuthenticationError,
                      'INVALID_CURRENCY': ExchangeError,
                      'INVALID_PERMISSION': AuthenticationError,
                      'INSUFFICIENT_FUNDS': InsufficientFunds,
                      'INVALID_CEILING_MARKET_BUY': InvalidOrder,
                      'INVALID_FIAT_ACCOUNT': InvalidOrder,
                      'INVALID_ORDER_TYPE': InvalidOrder,
                      'QUANTITY_NOT_PROVIDED': InvalidOrder,
                      'MIN_TRADE_REQUIREMENT_NOT_MET': InvalidOrder,
                      'ORDER_NOT_OPEN': OrderNotFound,
                      'INVALID_ORDER': InvalidOrder,
                      'UUID_INVALID': OrderNotFound,
                      'RATE_NOT_PROVIDED': InvalidOrder,  # createLimitBuyOrder('ETH/BTC', 1, 0)
                      'INVALID_MARKET': BadSymbol,  # {"success":false,"message":"INVALID_MARKET","result":null,"explanation":null}
                      'WHITELIST_VIOLATION_IP': PermissionDenied,
                      'DUST_TRADE_DISALLOWED_MIN_VALUE': InvalidOrder,
                      'RESTRICTED_MARKET': BadSymbol,
                      'We are down for scheduled maintenance, but we\u2019ll be back up shortly.': OnMaintenance,  # {"success":false,"message":"We are down for scheduled maintenance, but we\u2019ll be back up shortly.","result":null,"explanation":null}
                  },
                  'broad': {
                      'throttled': DDoSProtection,
                      'problem': ExchangeNotAvailable,
                  },
              },
              'options': {
                  'fetchTicker': {
                      'method': 'publicGetMarketsMarketSymbolTicker',  # publicGetMarketsMarketSymbolSummary
                  },
                  'fetchTickers': {
                      'method': 'publicGetMarketsTickers',  # publicGetMarketsSummaries
                  },
                  'parseOrderStatus': False,
                  'hasAlreadyAuthenticatedSuccessfully': False,  # a workaround for APIKEY_INVALID
                  'symbolSeparator': '-',
                  # With certain currencies, like
                  # AEON, BTS, GXS, NXT, SBD, STEEM, STR, XEM, XLM, XMR, XRP
                  # an additional tag / memo / payment id is usually required by exchanges.
                  # With Bittrex some currencies imply the "base address + tag" logic.
                  # The base address for depositing is stored on self.currencies[code]
                  # The base address identifies the exchange as the recipient
                  # while the tag identifies the user account within the exchange
                  # and the tag is retrieved with fetchDepositAddress.
                  'tag': {
                      'NXT': True,  # NXT, BURST
                      'CRYPTO_NOTE_PAYMENTID': True,  # AEON, XMR
                      'BITSHAREX': True,  # BTS
                      'RIPPLE': True,  # XRP
                      'NEM': True,  # XEM
                      'STELLAR': True,  # XLM
                      'STEEM': True,  # SBD, GOLOS
                      # https://github.com/ccxt/ccxt/issues/4794
                      # 'LISK': True,  # LSK
                  },
                  'subaccountId': None,
                  # see the implementation of fetchClosedOrdersV3 below
                  # 'fetchClosedOrdersMethod': 'fetch_closed_orders_v3',
                  'fetchClosedOrdersFilterBySince': True,
                  # 'createOrderMethod': 'create_order_v1',
              },
              'commonCurrencies': {
                  'BITS': 'SWIFT',
              },
          })
  
      def cost_to_precision(self, symbol, cost):
          return self.decimal_to_precision(cost, TRUNCATE, self.markets[symbol]['precision']['price'], DECIMAL_PLACES)
  
      def fee_to_precision(self, symbol, fee):
          return self.decimal_to_precision(fee, TRUNCATE, self.markets[symbol]['precision']['price'], DECIMAL_PLACES)
  
      def fetch_markets(self, params={}):
          response = self.publicGetMarkets(params)
          #
          #     [
          #         {
          #             "symbol":"LTC-BTC",
          #             "baseCurrencySymbol":"LTC",
          #             "quoteCurrencySymbol":"BTC",
          #             "minTradeSize":"0.01686767",
          #             "precision":8,
          #             "status":"ONLINE",  # "OFFLINE"
          #             "createdAt":"2014-02-13T00:00:00Z"
          #         },
          #         {
          #             "symbol":"VDX-USDT",
          #             "baseCurrencySymbol":"VDX",
          #             "quoteCurrencySymbol":"USDT",
          #             "minTradeSize":"300.00000000",
          #             "precision":8,
          #             "status":"ONLINE",  # "OFFLINE"
          #             "createdAt":"2019-05-23T00:41:21.843Z",
          #             "notice":"USDT has swapped to an ERC20-based token as of August 5, 2019."
          #         }
          #     ]
          #
          result = []
          for i in range(0, len(response)):
              market = response[i]
              baseId = self.safe_string(market, 'baseCurrencySymbol')
              quoteId = self.safe_string(market, 'quoteCurrencySymbol')
              id = self.safe_string(market, 'symbol')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = base + '/' + quote
              pricePrecision = self.safe_integer(market, 'precision', 8)
              precision = {
                  'amount': 8,
                  'price': pricePrecision,
              }
              status = self.safe_string(market, 'status')
              active = (status == 'ONLINE')
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'active': active,
                  'info': market,
                  'precision': precision,
                  'limits': {
                      'amount': {
                          'min': self.safe_float(market, 'minTradeSize'),
                          'max': None,
                      },
                      'price': {
                          'min': 1 / math.pow(10, precision['price']),
                          'max': None,
                      },
                      'cost': {
                          'min': None,
                          'max': None,
                      },
                  },
              })
          return result
  
      def fetch_balance(self, params={}):
          self.load_markets()
          balances = self.privateGetBalances(params)
          result = {'info': balances}
          indexed = self.index_by(balances, 'currencySymbol')
          currencyIds = list(indexed.keys())
          for i in range(0, len(currencyIds)):
              currencyId = currencyIds[i]
              code = self.safe_currency_code(currencyId)
              account = self.account()
              balance = indexed[currencyId]
              account['free'] = self.safe_float(balance, 'available')
              account['total'] = self.safe_float(balance, 'total')
              result[code] = account
          return self.parse_balance(result)
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          request = {
              'marketSymbol': self.market_id(symbol),
          }
          if limit is not None:
              if (limit != 1) and (limit != 25) and (limit != 500):
                  raise BadRequest(self.id + ' fetchOrderBook() limit argument must be None, 1, 25 or 100, default is 25')
              request['depth'] = limit
          response = self.publicGetMarketsMarketSymbolOrderbook(self.extend(request, params))
          #
          #     {
          #         "bid":[
          #             {"quantity":"0.01250000","rate":"10718.56200003"},
          #             {"quantity":"0.10000000","rate":"10718.56200002"},
          #             {"quantity":"0.39648292","rate":"10718.56200001"},
          #         ],
          #         "ask":[
          #             {"quantity":"0.05100000","rate":"10724.30099631"},
          #             {"quantity":"0.10000000","rate":"10724.30099632"},
          #             {"quantity":"0.26000000","rate":"10724.30099634"},
          #         ]
          #     }
          #
          sequence = self.safe_value_2(self.last_response_headers, 'sequence', 'Sequence')
          sequence = int(sequence[0]) if isinstance(sequence, list) else int(sequence)
          orderbook = self.parse_order_book(response, None, 'bid', 'ask', 'rate', 'quantity')
          orderbook['nonce'] = sequence
          return orderbook
  
      def fetch_currencies(self, params={}):
          response = self.publicGetCurrencies(params)
          #
          #     [
          #         {
          #             "symbol":"1ST",
          #             "name":"Firstblood",
          #             "coinType":"ETH_CONTRACT",
          #             "status":"ONLINE",
          #             "minConfirmations":36,
          #             "notice":"",
          #             "txFee":"4.50000000",
          #             "logoUrl":"https://bittrexblobstorage.blob.core.windows.net/public/5685a7be-1edf-4ba0-a313-b5309bb204f8.png",
          #             "prohibitedIn":[],
          #             "baseAddress":"0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98",
          #             "associatedTermsOfService":[]
          #         }
          #     ]
          #
          result = {}
          for i in range(0, len(response)):
              currency = response[i]
              id = self.safe_string(currency, 'symbol')
              code = self.safe_currency_code(id)
              precision = 8  # default precision, todo: fix "magic constants"
              fee = self.safe_float(currency, 'txFee')  # todo: redesign
              isActive = self.safe_string(currency, 'status')
              result[code] = {
                  'id': id,
                  'code': code,
                  'address': self.safe_string(currency, 'baseAddress'),
                  'info': currency,
                  'type': self.safe_string(currency, 'coinType'),
                  'name': self.safe_string(currency, 'name'),
                  'active': (isActive == 'ONLINE'),
                  'fee': fee,
                  'precision': precision,
                  'limits': {
                      'amount': {
                          'min': 1 / math.pow(10, precision),
                          'max': None,
                      },
                      'price': {
                          'min': 1 / math.pow(10, precision),
                          'max': None,
                      },
                      'cost': {
                          'min': None,
                          'max': None,
                      },
                      'withdraw': {
                          'min': fee,
                          'max': None,
                      },
                  },
              }
          return result
  
      def parse_ticker(self, ticker, market=None):
          #
          # ticker
          #
          #     {
          #         "symbol":"ETH-BTC",
          #         "lastTradeRate":"0.03284496",
          #         "bidRate":"0.03284523",
          #         "askRate":"0.03286857"
          #     }
          #
          # summary
          #
          #     {
          #         "symbol":"ETH-BTC",
          #         "high":"0.03369528",
          #         "low":"0.03282442",
          #         "volume":"4307.83794556",
          #         "quoteVolume":"143.08608869",
          #         "percentChange":"0.79",
          #         "updatedAt":"2020-09-29T07:36:57.823Z"
          #     }
          #
          timestamp = self.parse8601(self.safe_string(ticker, 'updatedAt'))
          symbol = None
          marketId = self.safe_string(ticker, 'symbol')
          if marketId is not None:
              if marketId in self.markets_by_id:
                  market = self.markets_by_id[marketId]
              else:
                  symbol = self.parse_symbol(marketId)
          if (symbol is None) and (market is not None):
              symbol = market['symbol']
          percentage = self.safe_float(ticker, 'percentChange')
          last = self.safe_float(ticker, 'lastTradeRate')
          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, 'bidRate'),
              'bidVolume': None,
              'ask': self.safe_float(ticker, 'askRate'),
              'askVolume': None,
              'vwap': None,
              'open': None,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': None,
              'percentage': percentage,
              'average': None,
              'baseVolume': self.safe_float(ticker, 'volume'),
              'quoteVolume': self.safe_float(ticker, 'quoteVolume'),
              'info': ticker,
          }
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          options = self.safe_value(self.options, 'fetchTickers', {})
          method = self.safe_string(options, 'method', 'publicGetMarketsTickers')
          response = getattr(self, method)(params)
          #
          # publicGetMarketsTickers
          #
          #     [
          #         {
          #             "symbol":"4ART-BTC",
          #             "lastTradeRate":"0.00000210",
          #             "bidRate":"0.00000210",
          #             "askRate":"0.00000215"
          #         }
          #     ]
          #
          # publicGetMarketsSummaries
          #
          #     [
          #         {
          #             "symbol":"4ART-BTC",
          #             "high":"0.00000206",
          #             "low":"0.00000196",
          #             "volume":"14871.32000233",
          #             "quoteVolume":"0.02932756",
          #             "percentChange":"1.48",
          #             "updatedAt":"2020-09-29T07:34:32.757Z"
          #         }
          #     ]
          #
          tickers = []
          for i in range(0, len(response)):
              ticker = self.parse_ticker(response[i])
              tickers.append(ticker)
          return self.filter_by_array(tickers, 'symbol', symbols)
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'marketSymbol': market['id'],
          }
          options = self.safe_value(self.options, 'fetchTicker', {})
          method = self.safe_string(options, 'method', 'publicGetMarketsMarketSymbolTicker')
          response = getattr(self, method)(self.extend(request, params))
          #
          # publicGetMarketsMarketSymbolTicker
          #
          #     {
          #         "symbol":"ETH-BTC",
          #         "lastTradeRate":"0.03284496",
          #         "bidRate":"0.03284523",
          #         "askRate":"0.03286857"
          #     }
          #
          #
          # publicGetMarketsMarketSymbolSummary
          #
          #     {
          #         "symbol":"ETH-BTC",
          #         "high":"0.03369528",
          #         "low":"0.03282442",
          #         "volume":"4307.83794556",
          #         "quoteVolume":"143.08608869",
          #         "percentChange":"0.79",
          #         "updatedAt":"2020-09-29T07:36:57.823Z"
          #     }
          #
          return self.parse_ticker(response, market)
  
      def parse_trade(self, trade, market=None):
          #
          # public fetchTrades
          #
          #     {
          #         "id":"9c5589db-42fb-436c-b105-5e2edcb95673",
          #         "executedAt":"2020-10-03T11:48:43.38Z",
          #         "quantity":"0.17939626",
          #         "rate":"0.03297952",
          #         "takerSide":"BUY"
          #     }
          #
          # private fetchOrderTrades
          #
          #     {
          #         "id": "aaa3e9bd-5b86-4a21-8b3d-1275c1d30b8e",
          #         "marketSymbol": "OMG-BTC",
          #         "executedAt": "2020-10-02T16:00:30.3Z",
          #         "quantity": "7.52710000",
          #         "rate": "0.00034907",
          #         "orderId": "3a3dbd33-3a30-4ae5-a41d-68d3c1ac537e",
          #         "commission": "0.00000525",
          #         "isTaker": False
          #     }
          #
          timestamp = self.parse8601(self.safe_string(trade, 'executedAt'))
          id = self.safe_string(trade, 'id')
          order = self.safe_string(trade, 'orderId')
          marketId = self.safe_string(trade, 'marketSymbol')
          symbol = self.safe_symbol(marketId, market, '-')
          quote = None
          if marketId is not None:
              if symbol in self.markets:
                  market = self.safe_value(self.markets, symbol, market)
                  quote = market['quote']
              else:
                  baseId, quoteId = marketId.split('-')
                  base = self.safe_currency_code(baseId)
                  quote = self.safe_currency_code(quoteId)
                  symbol = base + '/' + quote
          cost = None
          price = self.safe_float(trade, 'rate')
          amount = self.safe_float(trade, 'quantity')
          if amount is not None:
              if price is not None:
                  cost = price * amount
          takerOrMaker = None
          isTaker = self.safe_value(trade, 'isTaker')
          if isTaker is not None:
              takerOrMaker = 'taker' if isTaker else 'maker'
          fee = None
          feeCost = self.safe_float(trade, 'commission')
          if feeCost is not None:
              fee = {
                  'cost': feeCost,
                  'currency': quote,
              }
          side = self.safe_string_lower(trade, 'takerSide')
          return {
              'info': trade,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'id': id,
              'order': order,
              'takerOrMaker': takerOrMaker,
              'type': None,
              'side': side,
              'price': price,
              'amount': amount,
              'cost': cost,
              'fee': fee,
          }
  
      def fetch_time(self, params={}):
          response = self.publicGetPing(params)
          #
          #     {
          #         "serverTime": 1594596023162
          #     }
          #
          return self.safe_integer(response, 'serverTime')
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'marketSymbol': self.market_id(symbol),
          }
          response = self.publicGetMarketsMarketSymbolTrades(self.extend(request, params))
          #
          #     [
          #         {
          #             "id":"9c5589db-42fb-436c-b105-5e2edcb95673",
          #             "executedAt":"2020-10-03T11:48:43.38Z",
          #             "quantity":"0.17939626",
          #             "rate":"0.03297952",
          #             "takerSide":"BUY"
          #         }
          #     ]
          #
          return self.parse_trades(response, market, since, limit)
  
      def parse_ohlcv(self, ohlcv, market=None):
          #
          #     {
          #         "startsAt":"2020-06-12T02:35:00Z",
          #         "open":"0.02493753",
          #         "high":"0.02493753",
          #         "low":"0.02493753",
          #         "close":"0.02493753",
          #         "volume":"0.09590123",
          #         "quoteVolume":"0.00239153"
          #     }
          #
          return [
              self.parse8601(self.safe_string(ohlcv, 'startsAt')),
              self.safe_float(ohlcv, 'open'),
              self.safe_float(ohlcv, 'high'),
              self.safe_float(ohlcv, 'low'),
              self.safe_float(ohlcv, 'close'),
              self.safe_float(ohlcv, 'volume'),
          ]
  
      def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          reverseId = market['baseId'] + '-' + market['quoteId']
          request = {
              'candleInterval': self.timeframes[timeframe],
              'marketSymbol': reverseId,
          }
          method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalRecent'
          if since is not None:
              now = self.milliseconds()
              difference = abs(now - since)
              sinceDate = self.ymd(since)
              parts = sinceDate.split('-')
              sinceYear = self.safe_integer(parts, 0)
              sinceMonth = self.safe_integer(parts, 1)
              sinceDay = self.safe_integer(parts, 2)
              if timeframe == '1d':
                  # if the since argument is beyond one year into the past
                  if difference > 31622400000:
                      method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYear'
                      request['year'] = sinceYear
                  # request['year'] = year
              elif timeframe == '1h':
                  # if the since argument is beyond 31 days into the past
                  if difference > 2678400000:
                      method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYearMonth'
                      request['year'] = sinceYear
                      request['month'] = sinceMonth
              else:
                  # if the since argument is beyond 1 day into the past
                  if difference > 86400000:
                      method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYearMonthDay'
                      request['year'] = sinceYear
                      request['month'] = sinceMonth
                      request['day'] = sinceDay
          response = getattr(self, method)(self.extend(request, params))
          #
          #     [
          #         {"startsAt":"2020-06-12T02:35:00Z","open":"0.02493753","high":"0.02493753","low":"0.02493753","close":"0.02493753","volume":"0.09590123","quoteVolume":"0.00239153"},
          #         {"startsAt":"2020-06-12T02:40:00Z","open":"0.02491874","high":"0.02491874","low":"0.02490970","close":"0.02490970","volume":"0.04515695","quoteVolume":"0.00112505"},
          #         {"startsAt":"2020-06-12T02:45:00Z","open":"0.02490753","high":"0.02493143","low":"0.02490753","close":"0.02493143","volume":"0.17769640","quoteVolume":"0.00442663"}
          #     ]
          #
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['marketSymbol'] = market['id']
          response = self.privateGetOrdersOpen(self.extend(request, params))
          orders = self.parse_orders(response, market, since, limit)
          return self.filter_by_symbol(orders, symbol)
  
      def fetch_order_trades(self, id, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              'orderId': id,
          }
          response = self.privateGetOrdersOrderIdExecutions(self.extend(request, params))
          market = None
          if symbol is not None:
              market = self.market(symbol)
          return self.parse_trades(response, market, since, limit)
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          # A ceiling order is a market or limit order that allows you to specify
          # the amount of quote currency you want to spend(or receive, if selling)
          # instead of the quantity of the market currency(e.g. buy $100 USD of BTC
          # at the current market BTC price)
          self.load_markets()
          market = self.market(symbol)
          uppercaseType = type.upper()
          reverseId = market['baseId'] + '-' + market['quoteId']
          request = {
              'marketSymbol': reverseId,
              'direction': side.upper(),
              'type': uppercaseType,  # LIMIT, MARKET, CEILING_LIMIT, CEILING_MARKET
              # 'quantity': self.amount_to_precision(symbol, amount),  # required for limit orders, excluded for ceiling orders
              # 'ceiling': self.price_to_precision(symbol, price),  # required for ceiling orders, excluded for non-ceiling orders
              # 'limit': self.price_to_precision(symbol, price),  # required for limit orders, excluded for market orders
              # 'timeInForce': 'GOOD_TIL_CANCELLED',  # IMMEDIATE_OR_CANCEL, FILL_OR_KILL, POST_ONLY_GOOD_TIL_CANCELLED
              # 'useAwards': False,  # optional
          }
          isCeilingLimit = (uppercaseType == 'CEILING_LIMIT')
          isCeilingMarket = (uppercaseType == 'CEILING_MARKET')
          isCeilingOrder = isCeilingLimit or isCeilingMarket
          if isCeilingOrder:
              request['ceiling'] = self.price_to_precision(symbol, price)
              # bittrex only accepts IMMEDIATE_OR_CANCEL or FILL_OR_KILL for ceiling orders
              request['timeInForce'] = 'IMMEDIATE_OR_CANCEL'
          else:
              request['quantity'] = self.amount_to_precision(symbol, amount)
              if uppercaseType == 'LIMIT':
                  request['limit'] = self.price_to_precision(symbol, price)
                  request['timeInForce'] = 'GOOD_TIL_CANCELLED'
              else:
                  # bittrex does not allow GOOD_TIL_CANCELLED for market orders
                  request['timeInForce'] = 'IMMEDIATE_OR_CANCEL'
          response = self.privatePostOrders(self.extend(request, params))
          #
          #     {
          #         id: 'f03d5e98-b5ac-48fb-8647-dd4db828a297',
          #         marketSymbol: 'BTC-USDT',
          #         direction: 'SELL',
          #         type: 'LIMIT',
          #         quantity: '0.01',
          #         limit: '6000',
          #         timeInForce: 'GOOD_TIL_CANCELLED',
          #         fillQuantity: '0.00000000',
          #         commission: '0.00000000',
          #         proceeds: '0.00000000',
          #         status: 'OPEN',
          #         createdAt: '2020-03-18T02:37:33.42Z',
          #         updatedAt: '2020-03-18T02:37:33.42Z'
          #       }
          #
          return self.parse_order(response, market)
  
      def cancel_order(self, id, symbol=None, params={}):
          self.load_markets()
          request = {
              'orderId': id,
          }
          response = self.privateDeleteOrdersOrderId(self.extend(request, params))
          return self.extend(self.parse_order(response), {
              'id': id,
              'info': response,
              'status': 'canceled',
          })
  
      def cancel_all_orders(self, symbol=None, params={}):
          self.load_markets()
          request = {}
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['marketSymbol'] = market['id']
          response = self.privateDeleteOrdersOpen(self.extend(request, params))
          #
          #     [
          #         {
          #             "id":"66582be0-5337-4d8c-b212-c356dd525801",
          #             "statusCode":"SUCCESS",
          #             "result":{
          #                 "id":"66582be0-5337-4d8c-b212-c356dd525801",
          #                 "marketSymbol":"BTC-USDT",
          #                 "direction":"BUY",
          #                 "type":"LIMIT",
          #                 "quantity":"0.01000000",
          #                 "limit":"3000.00000000",
          #                 "timeInForce":"GOOD_TIL_CANCELLED",
          #                 "fillQuantity":"0.00000000",
          #                 "commission":"0.00000000",
          #                 "proceeds":"0.00000000",
          #                 "status":"CLOSED",
          #                 "createdAt":"2020-10-06T12:31:53.39Z",
          #                 "updatedAt":"2020-10-06T12:54:28.8Z",
          #                 "closedAt":"2020-10-06T12:54:28.8Z"
          #             }
          #         }
          #     ]
          #
          orders = []
          for i in range(0, len(response)):
              result = self.safe_value(response[i], 'result', {})
              orders.append(result)
          return self.parse_orders(orders, market)
  
      def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          # https://support.bittrex.com/hc/en-us/articles/115003723911
          request = {}
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['currencySymbol'] = currency['id']
          response = self.privateGetDepositsClosed(self.extend(request, params))
          # we cannot filter by `since` timestamp, as it isn't set by Bittrex
          # see https://github.com/ccxt/ccxt/issues/4067
          # return self.parse_transactions(response, currency, since, limit)
          return self.parse_transactions(response, currency, None, limit)
  
      def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          self.load_markets()
          # https://support.bittrex.com/hc/en-us/articles/115003723911
          request = {}
          currency = None
          if code is not None:
              currency = self.currency(code)
              request['currencySymbol'] = currency['id']
          response = self.privateGetWithdrawalsClosed(self.extend(request, params))
          return self.parse_transactions(response, currency, since, limit)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchDeposits
          #     {
          #         "id": "d00fdf2e-df9e-48f1-....",
          #         "currencySymbol": "BTC",
          #         "quantity": "0.00550000",
          #         "cryptoAddress": "1PhmYjnJPZH5NUwV8AU...",
          #         "txId": "d1f1afffe1b9b6614eaee7e8133c85d98...",
          #         "confirmations": 2,
          #         "updatedAt": "2020-01-12T16:49:30.41Z",
          #         "completedAt": "2020-01-12T16:49:30.41Z",
          #         "status": "COMPLETED",
          #         "source": "BLOCKCHAIN"
          #     }
          #
          # fetchWithdrawals
          #     {
          #         "PaymentUuid" : "e293da98-788c-4188-a8f9-8ec2c33fdfcf",
          #         "Currency" : "XC",
          #         "Amount" : 7513.75121715,
          #         "Address" : "EVnSMgAd7EonF2Dgc4c9K14L12RBaW5S5J",
          #         "Opened" : "2014-07-08T23:13:31.83",
          #         "Authorized" : True,
          #         "PendingPayment" : False,
          #         "TxCost" : 0.00002000,
          #         "TxId" : "b4a575c2a71c7e56d02ab8e26bb1ef0a2f6cf2094f6ca2116476a569c1e84f6e",
          #         "Canceled" : False,
          #         "InvalidAddress" : False
          #     }
          #
          id = self.safe_string(transaction, 'id')
          amount = self.safe_float(transaction, 'quantity')
          address = self.safe_string(transaction, 'cryptoAddress')
          txid = self.safe_string(transaction, 'txId')
          updated = self.parse8601(self.safe_string(transaction, 'updatedAt'))
          opened = self.parse8601(self.safe_string(transaction, 'createdAt'))
          timestamp = opened if opened else updated
          type = 'deposit' if (opened is None) else 'withdrawal'
          currencyId = self.safe_string(transaction, 'currencySymbol')
          code = self.safe_currency_code(currencyId, currency)
          status = 'pending'
          if type == 'deposit':
              #
              # deposits numConfirmations never reach the minConfirmations number
              # we set all of them to 'ok', otherwise they'd all be 'pending'
              #
              #     numConfirmations = self.safe_integer(transaction, 'Confirmations', 0)
              #     minConfirmations = self.safe_integer(currency['info'], 'MinConfirmation')
              #     if numConfirmations >= minConfirmations:
              #         status = 'ok'
              #     }
              #
              status = 'ok'
          else:
              responseStatus = self.safe_string(transaction, 'status')
              if responseStatus == 'ERROR_INVALID_ADDRESS':
                  status = 'failed'
              elif responseStatus == 'CANCELLED':
                  status = 'canceled'
              elif responseStatus == 'PENDING':
                  status = 'pending'
              elif responseStatus == 'AUTHORIZED' and (txid is not None):
                  status = 'ok'
          feeCost = self.safe_float(transaction, 'txCost')
          if feeCost is None:
              if type == 'deposit':
                  # according to https://support.bittrex.com/hc/en-us/articles/115000199651-What-fees-does-Bittrex-charge-
                  feeCost = 0
          return {
              'info': transaction,
              'id': id,
              'currency': code,
              'amount': amount,
              'address': address,
              'tag': None,
              'status': status,
              'type': type,
              'updated': updated,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'fee': {
                  'currency': code,
                  'cost': feeCost,
              },
          }
  
      def parse_symbol(self, id):
          quoteId, baseId = id.split(self.options['symbolSeparator'])
          base = self.safe_currency_code(baseId)
          quote = self.safe_currency_code(quoteId)
          return base + '/' + quote
  
      def parse_order(self, order, market=None):
          #
          #     {
          #         id: '1be35109-b763-44ce-b6ea-05b6b0735c0c',
          #         marketSymbol: 'LTC-ETH',
          #         direction: 'BUY',
          #         type: 'LIMIT',
          #         quantity: '0.50000000',
          #         limit: '0.17846699',
          #         timeInForce: 'GOOD_TIL_CANCELLED',
          #         fillQuantity: '0.50000000',
          #         commission: '0.00022286',
          #         proceeds: '0.08914915',
          #         status: 'CLOSED',
          #         createdAt: '2018-06-23T13:14:28.613Z',
          #         updatedAt: '2018-06-23T13:14:30.19Z',
          #         closedAt: '2018-06-23T13:14:30.19Z'
          #     }
          #
          marketSymbol = self.safe_string(order, 'marketSymbol')
          symbol = None
          feeCurrency = None
          if marketSymbol is not None:
              baseId, quoteId = marketSymbol.split('-')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = base + '/' + quote
              feeCurrency = quote
          direction = self.safe_string_lower(order, 'direction')
          createdAt = self.safe_string(order, 'createdAt')
          updatedAt = self.safe_string(order, 'updatedAt')
          closedAt = self.safe_string(order, 'closedAt')
          lastTradeTimestamp = None
          if closedAt is not None:
              lastTradeTimestamp = self.parse8601(closedAt)
          elif updatedAt:
              lastTradeTimestamp = self.parse8601(updatedAt)
          timestamp = self.parse8601(createdAt)
          type = self.safe_string_lower(order, 'type')
          quantity = self.safe_float(order, 'quantity')
          limit = self.safe_float(order, 'limit')
          fillQuantity = self.safe_float(order, 'fillQuantity')
          commission = self.safe_float(order, 'commission')
          proceeds = self.safe_float(order, 'proceeds')
          average = None
          remaining = None
          if fillQuantity is not None:
              if proceeds is not None:
                  if fillQuantity > 0:
                      average = proceeds / fillQuantity
                  elif proceeds == 0:
                      average = 0
              if quantity is not None:
                  remaining = quantity - fillQuantity
          status = self.safe_string_lower(order, 'status')
          if (status == 'closed') and (remaining is not None) and (remaining > 0):
              status = 'canceled'
          return {
              'id': self.safe_string(order, 'id'),
              'clientOrderId': None,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': lastTradeTimestamp,
              'symbol': symbol,
              'type': type,
              'side': direction,
              'price': limit,
              'cost': proceeds,
              'average': average,
              'amount': quantity,
              'filled': fillQuantity,
              'remaining': remaining,
              'status': status,
              'fee': {
                  'cost': commission,
                  'currency': feeCurrency,
              },
              'info': order,
              'trades': None,
          }
  
      def parse_orders(self, orders, market=None, since=None, limit=None, params={}):
          if self.options['fetchClosedOrdersFilterBySince']:
              return super(bittrex, self).parse_orders(orders, market, since, limit, params)
          else:
              return super(bittrex, self).parse_orders(orders, market, None, limit, params)
  
      def parse_order_status(self, status):
          statuses = {
              'CLOSED': 'closed',
              'OPEN': 'open',
              'CANCELLED': 'canceled',
              'CANCELED': 'canceled',
          }
          return self.safe_string(statuses, status, status)
  
      def fetch_order(self, id, symbol=None, params={}):
          self.load_markets()
          response = None
          try:
              request = {
                  'orderId': id,
              }
              response = self.privateGetOrdersOrderId(self.extend(request, params))
          except Exception as e:
              if self.last_json_response:
                  message = self.safe_string(self.last_json_response, 'message')
                  if message == 'UUID_INVALID':
                      raise OrderNotFound(self.id + ' fetchOrder() error: ' + self.last_http_response)
              raise e
          return self.parse_order(response)
  
      def order_to_trade(self, order):
          # self entire method should be moved to the base class
          timestamp = self.safe_integer_2(order, 'lastTradeTimestamp', 'timestamp')
          return {
              'id': self.safe_string(order, 'id'),
              'side': self.safe_string(order, 'side'),
              'order': self.safe_string(order, 'id'),
              'type': self.safe_string(order, 'type'),
              'price': self.safe_float(order, 'average'),
              'amount': self.safe_float(order, 'filled'),
              'cost': self.safe_float(order, 'cost'),
              'symbol': self.safe_string(order, 'symbol'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'fee': self.safe_value(order, 'fee'),
              'info': order,
              'takerOrMaker': None,
          }
  
      def orders_to_trades(self, orders):
          # self entire method should be moved to the base class
          result = []
          for i in range(0, len(orders)):
              result.append(self.order_to_trade(orders[i]))
          return result
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          if limit is not None:
              request['pageSize'] = limit
          if since is not None:
              request['startDate'] = self.ymdhms(since, 'T') + 'Z'
          market = None
          if symbol is not None:
              market = self.market(symbol)
              # because of self line we will have to rethink the entire v3
              # in other words, markets define all the rest of the API
              # and v3 market ids are reversed in comparison to v1
              # v3 has to be a completely separate implementation
              # otherwise we will have to shuffle symbols and currencies everywhere
              # which is prone to errors, as was shown here
              # https://github.com/ccxt/ccxt/pull/5219#issuecomment-499646209
              request['marketSymbol'] = market['base'] + '-' + market['quote']
          response = self.privateGetOrdersClosed(self.extend(request, params))
          orders = self.parse_orders(response, market)
          trades = self.orders_to_trades(orders)
          if symbol is not None:
              return self.filter_by_since_limit(trades, since, limit)
          else:
              return self.filter_by_symbol_since_limit(trades, symbol, since, limit)
  
      def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          if limit is not None:
              request['pageSize'] = limit
          if since is not None:
              request['startDate'] = self.ymdhms(since, 'T') + 'Z'
          market = None
          if symbol is not None:
              market = self.market(symbol)
              # because of self line we will have to rethink the entire v3
              # in other words, markets define all the rest of the API
              # and v3 market ids are reversed in comparison to v1
              # v3 has to be a completely separate implementation
              # otherwise we will have to shuffle symbols and currencies everywhere
              # which is prone to errors, as was shown here
              # https://github.com/ccxt/ccxt/pull/5219#issuecomment-499646209
              request['marketSymbol'] = market['base'] + '-' + market['quote']
          response = self.privateGetOrdersClosed(self.extend(request, params))
          orders = self.parse_orders(response, market, since, limit)
          if symbol is not None:
              return self.filter_by_symbol(orders, symbol)
          return orders
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          request = {
              'currencySymbol': currency['id'],
          }
          response = self.privateGetAddressesCurrencySymbol(self.extend(request, params))
          # {
          #     "status": "PROVISIONED",
          #     "currencySymbol": "BTC",
          #     "cryptoAddress": "1PhmYjnJPZH5NUwV8AUjqkeDkCBpbE2xqX"
          # }
          address = self.safe_string(response, 'cryptoAddress')
          message = self.safe_string(response, 'status')
          if not address or message == 'REQUESTED':
              raise AddressPending(self.id + ' the address for ' + code + ' is being generated(pending, not ready yet, retry again later)')
          tag = None
          if currency['type'] in self.options['tag']:
              tag = address
              address = currency['address']
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'tag': tag,
              'info': response,
          }
  
      def withdraw(self, code, amount, address, tag=None, params={}):
          self.check_address(address)
          self.load_markets()
          currency = self.currency(code)
          request = {
              'currencySymbol': currency['id'],
              'quantity': amount,
              'cryptoAddress': address,
          }
          if tag is not None:
              request['cryptoAddressTag'] = tag
          response = self.privatePostWithdrawals(self.extend(request, params))
          id = self.safe_string(response, 'id')
          return {
              'info': response,
              'id': id,
          }
  
      def sign(self, path, api='v3', method='GET', params={}, headers=None, body=None):
          url = self.implode_params(self.urls['api'][api], {
              'hostname': self.hostname,
          }) + '/'
          if api == 'private':
              url += self.version + '/'
              self.check_required_credentials()
              url += self.implode_params(path, params)
              params = self.omit(params, self.extract_params(path))
              hashString = ''
              if method == 'POST':
                  body = self.json(params)
                  hashString = body
              else:
                  if params:
                      url += '?' + self.rawencode(params)
              contentHash = self.hash(self.encode(hashString), 'sha512', 'hex')
              timestamp = str(self.milliseconds())
              auth = timestamp + url + method + contentHash
              subaccountId = self.safe_value(self.options, 'subaccountId')
              if subaccountId is not None:
                  auth += subaccountId
              signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha512)
              headers = {
                  'Api-Key': self.apiKey,
                  'Api-Timestamp': timestamp,
                  'Api-Content-Hash': contentHash,
                  'Api-Signature': signature,
              }
              if subaccountId is not None:
                  headers['Api-Subaccount-Id'] = subaccountId
              if method == 'POST':
                  headers['Content-Type'] = 'application/json'
          else:
              if api == 'public':
                  url += self.version + '/'
              url += self.implode_params(path, params)
              params = self.omit(params, self.extract_params(path))
              if params:
                  url += '?' + self.urlencode(params)
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
          if response is None:
              return  # fallback to default error handler
          #
          #     {success: False, message: "message"}
          #
          if body[0] == '{':
              feedback = self.id + ' ' + body
              success = self.safe_value(response, 'success')
              if success is None:
                  code = self.safe_string(response, 'code')
                  if code is not None:
                      self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
                      self.throw_broadly_matched_exception(self.exceptions['broad'], code, feedback)
                  # raise ExchangeError(self.id + ' malformed response ' + self.json(response))
                  return
              if isinstance(success, basestring):
                  # bleutrade uses string instead of boolean
                  success = (success == 'true')
              if not success:
                  message = self.safe_string(response, 'message')
                  if message == 'APIKEY_INVALID':
                      if self.options['hasAlreadyAuthenticatedSuccessfully']:
                          raise DDoSProtection(feedback)
                      else:
                          raise AuthenticationError(feedback)
                  # https://github.com/ccxt/ccxt/issues/4932
                  # the following two lines are now redundant, see line 171 in describe()
                  #
                  #     if message == 'DUST_TRADE_DISALLOWED_MIN_VALUE_50K_SAT':
                  #         raise InvalidOrder(self.id + ' order cost should be over 50k satoshi ' + self.json(response))
                  #
                  if message == 'INVALID_ORDER':
                      # Bittrex will return an ambiguous INVALID_ORDER message
                      # upon canceling already-canceled and closed orders
                      # therefore self special case for cancelOrder
                      # url = 'https://bittrex.com/api/v1.1/market/cancel?apikey=API_KEY&uuid=ORDER_UUID'
                      cancel = 'cancel'
                      indexOfCancel = url.find(cancel)
                      if indexOfCancel >= 0:
                          urlParts = url.split('?')
                          numParts = len(urlParts)
                          if numParts > 1:
                              query = urlParts[1]
                              params = query.split('&')
                              numParams = len(params)
                              orderId = None
                              for i in range(0, numParams):
                                  param = params[i]
                                  keyValue = param.split('=')
                                  if keyValue[0] == 'uuid':
                                      orderId = keyValue[1]
                                      break
                              if orderId is not None:
                                  raise OrderNotFound(self.id + ' cancelOrder ' + orderId + ' ' + self.json(response))
                              else:
                                  raise OrderNotFound(self.id + ' cancelOrder ' + self.json(response))
                  self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
                  if message is not None:
                      self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
                  raise ExchangeError(feedback)
  