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 base64
  import hashlib
  import math
  import json
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.errors import OrderNotCached
  from ccxt.base.errors import InvalidNonce
  
  
  class cryptopia (Exchange):
  
      def describe(self):
          return self.deep_extend(super(cryptopia, self).describe(), {
              'id': 'cryptopia',
              'name': 'Cryptopia',
              'rateLimit': 1500,
              'countries': ['NZ'],  # New Zealand
              'parseJsonResponse': False,
              'has': {
                  'CORS': False,
                  'createMarketOrder': False,
                  'fetchClosedOrders': 'emulated',
                  'fetchCurrencies': True,
                  'fetchDepositAddress': True,
                  'fetchMyTrades': True,
                  'fetchTransactions': False,
                  'fetchWithdrawals': True,
                  'fetchDeposits': True,
                  'fetchOHLCV': True,
                  'fetchOrder': 'emulated',
                  'fetchOrderBooks': True,
                  'fetchOrders': 'emulated',
                  'fetchOpenOrders': True,
                  'fetchTickers': True,
                  'deposit': True,
                  'withdraw': True,
              },
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/29484394-7b4ea6e2-84c6-11e7-83e5-1fccf4b2dc81.jpg',
                  'api': {
                      'public': 'https://www.cryptopia.co.nz/api',
                      'private': 'https://www.cryptopia.co.nz/api',
                      'web': 'https://www.cryptopia.co.nz',
                  },
                  'www': 'https://www.cryptopia.co.nz',
                  'referral': 'https://www.cryptopia.co.nz/Register?referrer=kroitor',
                  'doc': [
                      'https://support.cryptopia.co.nz/csm?id=kb_article&sys_id=a75703dcdbb9130084ed147a3a9619bc',
                      'https://support.cryptopia.co.nz/csm?id=kb_article&sys_id=40e9c310dbf9130084ed147a3a9619eb',
                  ],
              },
              'timeframes': {
                  '15m': 15,
                  '30m': 30,
                  '1h': 60,
                  '2h': 120,
                  '4h': 240,
                  '12h': 720,
                  '1d': 1440,
                  '1w': 10080,
              },
              'api': {
                  'web': {
                      'get': [
                          'Exchange/GetTradePairChart',
                      ],
                  },
                  'public': {
                      'get': [
                          'GetCurrencies',
                          'GetTradePairs',
                          'GetMarkets',
                          'GetMarkets/{id}',
                          'GetMarkets/{hours}',
                          'GetMarkets/{id}/{hours}',
                          'GetMarket/{id}',
                          'GetMarket/{id}/{hours}',
                          'GetMarketHistory/{id}',
                          'GetMarketHistory/{id}/{hours}',
                          'GetMarketOrders/{id}',
                          'GetMarketOrders/{id}/{count}',
                          'GetMarketOrderGroups/{ids}',
                          'GetMarketOrderGroups/{ids}/{count}',
                      ],
                  },
                  'private': {
                      'post': [
                          'CancelTrade',
                          'GetBalance',
                          'GetDepositAddress',
                          'GetOpenOrders',
                          'GetTradeHistory',
                          'GetTransactions',
                          'SubmitTip',
                          'SubmitTrade',
                          'SubmitTransfer',
                          'SubmitWithdraw',
                      ],
                  },
              },
              'commonCurrencies': {
                  'ACC': 'AdCoin',
                  'BAT': 'BatCoin',
                  'BEAN': 'BITB',  # rebranding, see issue  #3380
                  'BLZ': 'BlazeCoin',
                  'BTG': 'Bitgem',
                  'CAN': 'CanYaCoin',
                  'CAT': 'Catcoin',
                  'CC': 'CCX',
                  'CMT': 'Comet',
                  'EPC': 'ExperienceCoin',
                  'FCN': 'Facilecoin',
                  'FT': 'Fabric Token',
                  'FUEL': 'FC2',  # FuelCoin != FUEL
                  'HAV': 'Havecoin',
                  'HC': 'Harvest Masternode Coin',  # != HyperCash
                  'HSR': 'HC',
                  'KARM': 'KARMA',
                  'LBTC': 'LiteBitcoin',
                  'LDC': 'LADACoin',
                  'MARKS': 'Bitmark',
                  'NET': 'NetCoin',
                  'PLC': 'Polcoin',
                  'RED': 'RedCoin',
                  'STC': 'StopTrumpCoin',
                  'QBT': 'Cubits',
                  'WRC': 'WarCoin',
              },
              'options': {
                  'fetchTickersErrors': True,
              },
          })
  
      def fetch_markets(self, params={}):
          response = self.publicGetGetTradePairs()
          result = []
          markets = response['Data']
          for i in range(0, len(markets)):
              market = markets[i]
              numericId = market['Id']
              label = market['Label']
              baseId = market['Symbol']
              quoteId = market['BaseSymbol']
              base = self.common_currency_code(baseId)
              quote = self.common_currency_code(quoteId)
              symbol = base + '/' + quote
              id = baseId + '_' + quoteId
              precision = {
                  'amount': 8,
                  'price': 8,
              }
              lot = market['MinimumTrade']
              priceLimits = {
                  'min': market['MinimumPrice'],
                  'max': market['MaximumPrice'],
              }
              amountLimits = {
                  'min': lot,
                  'max': market['MaximumTrade'],
              }
              limits = {
                  'amount': amountLimits,
                  'price': priceLimits,
                  'cost': {
                      'min': market['MinimumBaseTrade'],
                      'max': None,
                  },
              }
              active = market['Status'] == 'OK'
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'numericId': numericId,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'info': market,
                  'maker': market['TradeFee'] / 100,
                  'taker': market['TradeFee'] / 100,
                  'active': active,
                  'precision': precision,
                  'limits': limits,
                  'label': label,
              })
          self.options['marketsByLabel'] = self.index_by(result, 'label')
          return result
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          response = self.publicGetGetMarketOrdersId(self.extend({
              'id': self.market_id(symbol),
          }, params))
          orderbook = response['Data']
          return self.parse_order_book(orderbook, None, 'Buy', 'Sell', 'Price', 'Volume')
  
      def fetch_ohlcv(self, symbol, timeframe='15m', since=None, limit=None, params={}):
          dataRange = 0
          if since is not None:
              dataRanges = [
                  86400,
                  172800,
                  604800,
                  1209600,
                  2592000,
                  7776000,
                  15552000,
              ]
              numDataRanges = len(dataRanges)
              now = self.seconds()
              sinceSeconds = int(since / 1000)
              for i in range(1, numDataRanges):
                  if (now - sinceSeconds) > dataRanges[i]:
                      dataRange = i
          self.load_markets()
          market = self.market(symbol)
          request = {
              'tradePairId': market['numericId'],
              'dataRange': dataRange,
              'dataGroup': self.timeframes[timeframe],
          }
          response = self.webGetExchangeGetTradePairChart(self.extend(request, params))
          candles = response['Candle']
          volumes = response['Volume']
          for i in range(0, len(candles)):
              candles[i].append(volumes[i]['basev'])
          return self.parse_ohlcvs(candles, market, timeframe, since, limit)
  
      def join_market_ids(self, ids, glue='-'):
          result = str(ids[0])
          for i in range(1, len(ids)):
              result += glue + str(ids[i])
          return result
  
      def fetch_order_books(self, symbols=None, params={}):
          self.load_markets()
          if symbols is None:
              raise ExchangeError(self.id + ' fetchOrderBooks requires the symbols argument as of May 2018(up to 5 symbols at max)')
          numSymbols = len(symbols)
          if numSymbols > 5:
              raise ExchangeError(self.id + ' fetchOrderBooks accepts 5 symbols at max')
          ids = self.join_market_ids(self.market_ids(symbols))
          response = self.publicGetGetMarketOrderGroupsIds(self.extend({
              'ids': ids,
          }, params))
          orderbooks = response['Data']
          result = {}
          for i in range(0, len(orderbooks)):
              orderbook = orderbooks[i]
              id = self.safe_string(orderbook, 'Market')
              symbol = id
              if id in self.markets_by_id:
                  market = self.markets_by_id[id]
                  symbol = market['symbol']
              result[symbol] = self.parse_order_book(orderbook, None, 'Buy', 'Sell', 'Price', 'Volume')
          return result
  
      def parse_ticker(self, ticker, market=None):
          timestamp = self.milliseconds()
          symbol = None
          if market is not None:
              symbol = market['symbol']
          open = self.safe_float(ticker, 'Open')
          last = self.safe_float(ticker, 'LastPrice')
          change = last - open
          baseVolume = self.safe_float(ticker, 'Volume')
          quoteVolume = self.safe_float(ticker, 'BaseVolume')
          vwap = None
          if quoteVolume is not None:
              if baseVolume is not None:
                  if baseVolume > 0:
                      vwap = quoteVolume / baseVolume
          return {
              'symbol': symbol,
              'info': ticker,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_float(ticker, 'High'),
              'low': self.safe_float(ticker, 'Low'),
              'bid': self.safe_float(ticker, 'BidPrice'),
              'bidVolume': None,
              'ask': self.safe_float(ticker, 'AskPrice'),
              'askVolume': None,
              'vwap': vwap,
              'open': open,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': change,
              'percentage': self.safe_float(ticker, 'Change'),
              'average': self.sum(last, open) / 2,
              'baseVolume': baseVolume,
              'quoteVolume': quoteVolume,
          }
  
      def fetch_ticker(self, symbol, params={}):
          self.load_markets()
          market = self.market(symbol)
          response = self.publicGetGetMarketId(self.extend({
              'id': market['id'],
          }, params))
          ticker = response['Data']
          return self.parse_ticker(ticker, market)
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          response = self.publicGetGetMarkets(params)
          result = {}
          tickers = response['Data']
          for i in range(0, len(tickers)):
              ticker = tickers[i]
              id = ticker['Label'].replace('/', '_')
              recognized = (id in list(self.markets_by_id.keys()))
              if not recognized:
                  if self.options['fetchTickersErrors']:
                      raise ExchangeError(self.id + ' fetchTickers() returned unrecognized pair id ' + str(id))
              else:
                  market = self.markets_by_id[id]
                  symbol = market['symbol']
                  result[symbol] = self.parse_ticker(ticker, market)
          return self.filter_by_array(result, 'symbol', symbols)
  
      def parse_trade(self, trade, market=None):
          timestamp = None
          if 'Timestamp' in trade:
              timestamp = trade['Timestamp'] * 1000
          elif 'TimeStamp' in trade:
              timestamp = self.parse8601(trade['TimeStamp'])
          price = self.safe_float(trade, 'Price')
          if not price:
              price = self.safe_float(trade, 'Rate')
          cost = self.safe_float(trade, 'Total')
          id = self.safe_string(trade, 'TradeId')
          if market is None:
              marketId = self.safe_string(trade, 'Market')
              marketId = marketId.replace('/', '_')
              if marketId in self.markets_by_id:
                  market = self.markets_by_id[marketId]
          symbol = None
          fee = None
          if market is not None:
              symbol = market['symbol']
              if 'Fee' in trade:
                  fee = {
                      'currency': market['quote'],
                      'cost': trade['Fee'],
                  }
          return {
              'id': id,
              'info': trade,
              'order': None,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'type': 'limit',
              'side': trade['Type'].lower(),
              'price': price,
              'cost': cost,
              'amount': trade['Amount'],
              'fee': fee,
          }
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          hours = 24  # the default
          if since is not None:
              elapsed = self.milliseconds() - since
              hour = 1000 * 60 * 60
              hours = int(int(math.ceil(elapsed / hour)))
          request = {
              'id': market['id'],
              'hours': hours,
          }
          response = self.publicGetGetMarketHistoryIdHours(self.extend(request, params))
          trades = response['Data']
          return self.parse_trades(trades, market, since, limit)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchWithdrawals
          #
          #     {
          #         Id: 937355,
          #         Currency: 'BTC',
          #         TxId: '5ba7784576cee48bfb9d1524abf7bdade3de65e0f2f9cdd25f7bef2c506cf296',
          #         Type: 'Withdraw',
          #         Amount: 0.7,
          #         Fee: 0,
          #         Status: 'Complete',
          #         Confirmations: 0,
          #         Timestamp: '2017-10-10T18:39:03.8928376',
          #         Address: '14KyZTusAZZGEmZzxsWf4pee7ThtA2iv2E',
          #     }
          #
          # fetchDeposits
          #     {
          #         Id: 7833741,
          #         Currency: 'BCH',
          #         TxId: '0000000000000000011865af4122fe3b144e2cbeea86142e8ff2fb4107352d43',
          #         Type: 'Deposit',
          #         Amount: 0.0003385,
          #         Fee: 0,
          #         Status: 'Confirmed',
          #         Confirmations: 6,
          #         Timestamp: '2017-08-01T16:19:24',
          #         Address: null
          #     }
          #
          timestamp = self.parse8601(self.safe_string(transaction, 'Timestamp'))
          code = None
          currencyId = self.safe_string(transaction, 'Currency')
          currency = self.safe_value(self.currencies_by_id, currencyId)
          if currency is None:
              code = self.common_currency_code(currencyId)
          if currency is not None:
              code = currency['code']
          status = self.safe_string(transaction, 'Status')
          txid = self.safe_string(transaction, 'TxId')
          if status is not None:
              status = self.parse_transaction_status(status)
          id = self.safe_string(transaction, 'Id')
          type = self.parse_transaction_type(self.safe_string(transaction, 'Type'))
          amount = self.safe_float(transaction, 'Amount')
          address = self.safe_string(transaction, 'Address')
          feeCost = self.safe_float(transaction, 'Fee')
          return {
              'info': transaction,
              'id': id,
              'currency': code,
              'amount': amount,
              'address': address,
              'tag': None,
              'status': status,
              'type': type,
              'updated': None,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'fee': {
                  'currency': code,
                  'cost': feeCost,
              },
          }
  
      def parse_transaction_status(self, status):
          statuses = {
              'Confirmed': 'ok',
              'Complete': 'ok',
              'Pending': 'pending',
          }
          return self.safe_string(statuses, status, status)
  
      def parse_transaction_type(self, type):
          types = {
              'Withdraw': 'withdrawal',
              'Deposit': 'deposit',
          }
          return self.safe_string(types, type, type)
  
      def fetch_transactions_by_type(self, type, code=None, since=None, limit=None, params={}):
          request = {
              'type': 'Deposit' if (type == 'deposit') else 'Withdraw',
          }
          response = self.privatePostGetTransactions(self.extend(request, params))
          return self.parseTransactions(response['Data'], code, since, limit)
  
      def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          return self.fetch_transactions_by_type('withdrawal', code, since, limit, params)
  
      def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          return self.fetch_transactions_by_type('deposit', code, since, limit, params)
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {}
          market = None
          if symbol is not None:
              market = self.market(symbol)
              request['Market'] = market['id']
          if limit is not None:
              request['Count'] = limit  # default 100
          response = self.privatePostGetTradeHistory(self.extend(request, params))
          return self.parse_trades(response['Data'], market, since, limit)
  
      def fetch_currencies(self, params={}):
          response = self.publicGetGetCurrencies(params)
          currencies = response['Data']
          result = {}
          for i in range(0, len(currencies)):
              currency = currencies[i]
              id = currency['Symbol']
              # todo: will need to rethink the fees
              # to add support for multiple withdrawal/deposit methods and
              # differentiated fees for each particular method
              precision = 8  # default precision, todo: fix "magic constants"
              code = self.common_currency_code(id)
              active = (currency['ListingStatus'] == 'Active')
              status = currency['Status'].lower()
              if status != 'ok':
                  active = False
              result[code] = {
                  'id': id,
                  'code': code,
                  'info': currency,
                  'name': currency['Name'],
                  'active': active,
                  'status': status,
                  'fee': currency['WithdrawFee'],
                  'precision': precision,
                  'limits': {
                      'amount': {
                          'min': math.pow(10, -precision),
                          'max': math.pow(10, precision),
                      },
                      'price': {
                          'min': math.pow(10, -precision),
                          'max': math.pow(10, precision),
                      },
                      'cost': {
                          'min': currency['MinBaseTrade'],
                          'max': None,
                      },
                      'withdraw': {
                          'min': currency['MinWithdraw'],
                          'max': currency['MaxWithdraw'],
                      },
                  },
              }
          return result
  
      def fetch_balance(self, params={}):
          self.load_markets()
          response = self.privatePostGetBalance(params)
          balances = response['Data']
          result = {'info': response}
          for i in range(0, len(balances)):
              balance = balances[i]
              code = balance['Symbol']
              currency = self.common_currency_code(code)
              account = {
                  'free': balance['Available'],
                  'used': 0.0,
                  'total': balance['Total'],
              }
              account['used'] = account['total'] - account['free']
              result[currency] = account
          return self.parse_balance(result)
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          if type == 'market':
              raise ExchangeError(self.id + ' allows limit orders only')
          self.load_markets()
          market = self.market(symbol)
          # price = float(price)
          # amount = float(amount)
          request = {
              'Market': market['id'],
              'Type': self.capitalize(side),
              # 'Rate': self.price_to_precision(symbol, price),
              # 'Amount': self.amount_to_precision(symbol, amount),
              'Rate': price,
              'Amount': amount,
          }
          response = self.privatePostSubmitTrade(self.extend(request, params))
          if not response:
              raise ExchangeError(self.id + ' createOrder returned unknown error: ' + self.json(response))
          id = None
          filled = 0.0
          status = 'open'
          if 'Data' in response:
              if 'OrderId' in response['Data']:
                  if response['Data']['OrderId']:
                      id = str(response['Data']['OrderId'])
                  else:
                      filled = amount
                      status = 'closed'
          order = {
              'id': id,
              'timestamp': None,
              'datetime': None,
              'lastTradeTimestamp': None,
              'status': status,
              'symbol': symbol,
              'type': type,
              'side': side,
              'price': price,
              'cost': price * amount,
              'amount': amount,
              'remaining': amount - filled,
              'filled': filled,
              'fee': None,
              # 'trades': self.parse_trades(order['trades'], market),
          }
          if id:
              self.orders[id] = order
          return self.extend({'info': response}, order)
  
      def cancel_order(self, id, symbol=None, params={}):
          self.load_markets()
          response = None
          try:
              response = self.privatePostCancelTrade(self.extend({
                  'Type': 'Trade',
                  'OrderId': id,
              }, params))
              # We do not know if it is indeed canceled, but cryptopia lacks any
              # reasonable method to get information on executed or canceled order.
              if id in self.orders:
                  self.orders[id]['status'] = 'canceled'
          except Exception as e:
              if self.last_json_response:
                  message = self.safe_string(self.last_json_response, 'Error')
                  if message:
                      if message.find('does not exist') >= 0:
                          raise OrderNotFound(self.id + ' cancelOrder() error: ' + self.last_http_response)
              raise e
          return self.parse_order(response)
  
      def parse_order(self, order, market=None):
          symbol = None
          if market is not None:
              symbol = market['symbol']
          elif 'Market' in order:
              id = order['Market']
              if id in self.markets_by_id:
                  market = self.markets_by_id[id]
                  symbol = market['symbol']
              else:
                  if id in self.options['marketsByLabel']:
                      market = self.options['marketsByLabel'][id]
                      symbol = market['symbol']
          timestamp = self.parse8601(self.safe_string(order, 'TimeStamp'))
          amount = self.safe_float(order, 'Amount')
          remaining = self.safe_float(order, 'Remaining')
          filled = None
          if amount is not None and remaining is not None:
              filled = amount - remaining
          id = self.safe_value(order, 'OrderId')
          if id is not None:
              id = str(id)
          side = self.safe_string(order, 'Type')
          if side is not None:
              side = side.lower()
          return {
              'id': id,
              'info': self.omit(order, 'status'),
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': None,
              'status': self.safe_string(order, 'status'),
              'symbol': symbol,
              'type': 'limit',
              'side': side,
              'price': self.safe_float(order, 'Rate'),
              'cost': self.safe_float(order, 'Total'),
              'amount': amount,
              'filled': filled,
              'remaining': remaining,
              'fee': None,
              # 'trades': self.parse_trades(order['trades'], market),
          }
  
      def fetch_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          market = None
          request = {
              # 'Market': market['id'],
              # 'TradePairId': market['id'],  # Cryptopia identifier(not required if 'Market' supplied)
              # 'Count': 100,  # default = 100
          }
          if symbol is not None:
              market = self.market(symbol)
              request['Market'] = market['id']
          response = self.privatePostGetOpenOrders(self.extend(request, params))
          orders = []
          for i in range(0, len(response['Data'])):
              orders.append(self.extend(response['Data'][i], {'status': 'open'}))
          openOrders = self.parse_orders(orders, market)
          for j in range(0, len(openOrders)):
              self.orders[openOrders[j]['id']] = openOrders[j]
          openOrdersIndexedById = self.index_by(openOrders, 'id')
          cachedOrderIds = list(self.orders.keys())
          result = []
          for k in range(0, len(cachedOrderIds)):
              id = cachedOrderIds[k]
              if id in openOrdersIndexedById:
                  self.orders[id] = self.extend(self.orders[id], openOrdersIndexedById[id])
              else:
                  order = self.orders[id]
                  if order['status'] == 'open':
                      if (symbol is None) or (order['symbol'] == symbol):
                          self.orders[id] = self.extend(order, {
                              'status': 'closed',
                              'cost': order['amount'] * order['price'],
                              'filled': order['amount'],
                              'remaining': 0.0,
                          })
              order = self.orders[id]
              if (symbol is None) or (order['symbol'] == symbol):
                  result.append(order)
          return self.filter_by_since_limit(result, since, limit)
  
      def fetch_order(self, id, symbol=None, params={}):
          id = str(id)
          orders = self.fetch_orders(symbol, None, None, params)
          for i in range(0, len(orders)):
              if orders[i]['id'] == id:
                  return orders[i]
          raise OrderNotCached(self.id + ' order ' + id + ' not found in cached .orders, fetchOrder requires .orders(de)serialization implemented for self method to work properly')
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          orders = self.fetch_orders(symbol, since, limit, params)
          result = []
          for i in range(0, len(orders)):
              if orders[i]['status'] == 'open':
                  result.append(orders[i])
          return result
  
      def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}):
          orders = self.fetch_orders(symbol, since, limit, params)
          result = []
          for i in range(0, len(orders)):
              if orders[i]['status'] == 'closed':
                  result.append(orders[i])
          return result
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          currency = self.currency(code)
          response = self.privatePostGetDepositAddress(self.extend({
              'Currency': currency['id'],
          }, params))
          address = self.safe_string(response['Data'], 'BaseAddress')
          tag = self.safe_string(response['Data'], 'Address')
          if (address is None) or len((address) < 1):
              address = tag
              tag = None
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'tag': tag,
              'info': response,
          }
  
      def withdraw(self, code, amount, address, tag=None, params={}):
          self.load_markets()
          currency = self.currency(code)
          self.check_address(address)
          request = {
              'Currency': currency['id'],
              'Amount': amount,
              'Address': address,  # Address must exist in you AddressBook in security settings
          }
          if tag:
              request['PaymentId'] = tag
          response = self.privatePostSubmitWithdraw(self.extend(request, params))
          return {
              'info': response,
              'id': response['Data'],
          }
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          url = self.urls['api'][api] + '/' + self.implode_params(path, params)
          query = self.omit(params, self.extract_params(path))
          if api == 'private':
              self.check_required_credentials()
              nonce = str(self.nonce())
              body = self.json(query, {'convertArraysToObjects': True})
              hash = self.hash(self.encode(body), 'md5', 'base64')
              secret = base64.b64decode(self.secret)
              uri = self.encode_uri_component(url)
              lowercase = uri.lower()
              hash = self.binary_to_string(hash)
              payload = self.apiKey + method + lowercase + nonce + hash
              signature = self.hmac(self.encode(payload), secret, hashlib.sha256, 'base64')
              auth = 'amx ' + self.apiKey + ':' + self.binary_to_string(signature) + ':' + nonce
              headers = {
                  'Content-Type': 'application/json',
                  'Authorization': auth,
              }
          else:
              if query:
                  url += '?' + self.urlencode(query)
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      def nonce(self):
          return self.milliseconds()
  
      def handle_errors(self, code, reason, url, method, headers, body, response=None):
          if not isinstance(body, basestring):
              return  # fallback to default error handler
          if len(body) < 2:
              return  # fallback to default error handler
          fixedJSONString = self.sanitize_broken_json_string(body)
          if fixedJSONString[0] == '{':
              response = json.loads(fixedJSONString)
              if 'Success' in response:
                  success = self.safe_value(response, 'Success')
                  if success is not None:
                      if not success:
                          error = self.safe_string(response, 'Error')
                          feedback = self.id
                          if isinstance(error, basestring):
                              feedback = feedback + ' ' + error
                              if error.find('Invalid trade amount') >= 0:
                                  raise InvalidOrder(feedback)
                              if error.find('No matching trades found') >= 0:
                                  raise OrderNotFound(feedback)
                              if error.find('does not exist') >= 0:
                                  raise OrderNotFound(feedback)
                              if error.find('Insufficient Funds') >= 0:
                                  raise InsufficientFunds(feedback)
                              if error.find('Nonce has already been used') >= 0:
                                  raise InvalidNonce(feedback)
                          else:
                              feedback = feedback + ' ' + fixedJSONString
                          raise ExchangeError(feedback)
  
      def sanitize_broken_json_string(self, jsonString):
          # sometimes cryptopia will return a unicode symbol before actual JSON string.
          indexOfBracket = jsonString.find('{')
          if indexOfBracket >= 0:
              return jsonString[indexOfBracket:]
          return jsonString
  
      def request(self, path, api='public', method='GET', params={}, headers=None, body=None):
          response = self.fetch2(path, api, method, params, headers, body)
          return self.parse_if_json_encoded_object(self.sanitize_broken_json_string(response))
  