text: # -*- coding: utf-8 -*-
  
  # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
  
  from ccxt.base.exchange import Exchange
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import AuthenticationError
  from ccxt.base.errors import ArgumentsRequired
  from ccxt.base.errors import BadRequest
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import InvalidOrder
  from ccxt.base.errors import OrderNotFound
  from ccxt.base.decimal_to_precision import DECIMAL_PLACES
  
  
  class bitclude(Exchange):
  
      def describe(self):
          return self.deep_extend(super(bitclude, self).describe(), {
              'id': 'bitclude',
              'name': 'Bitclude',
              'countries': ['PL'],
              'rateLimit': 2000,
              'certified': False,
              'pro': False,
              'urls': {
                  'api': {
                      'public': 'https://api.bitclude.com/',
                      'private': 'https://api.bitclude.com/',
                  },
                  'www': 'https://bitclude.com',
                  'doc': 'https://docs.bitclude.com',
              },
              'requiredCredentials': {
                  'apiKey': True,
                  'secret': False,
                  'uid': True,
              },
              'has': {
                  'fetchMarkets': 'emulated',
                  'fetchCurrencies': True,  # private
                  'cancelAllOrders': False,
                  'fetchClosedOrders': False,
                  'createDepositAddress': True,
                  'fetchDepositAddress': 'emulated',
                  'fetchDeposits': True,
                  'fetchFundingFees': 'emulated',
                  'fetchMyTrades': True,
                  'fetchOHLCV': False,
                  'fetchOpenOrders': True,
                  'fetchOrder': False,
                  'fetchOrderBook': True,
                  'fetchOrders': False,
                  'fetchTickers': True,
                  'fetchTicker': 'emulated',
                  'fetchTrades': True,
                  'fetchTradingFees': False,
                  'fetchWithdrawals': False,
                  'withdraw': False,
              },
              'api': {
                  'public': {
                      'get': [
                          'stats/ticker.json',
                          'stats/orderbook_{base}{quote}.json',
                          'stats/history_{base}{quote}.json',
                      ],
                  },
                  'private': {
                      'get': [
                          '',
                      ],
                  },
              },
              'exceptions': {
                  # stolen, todo rewrite
                  'exact': {
                      'Not enough balances': InsufficientFunds,  # {"error":"Not enough balances","success":false}
                      'InvalidPrice': InvalidOrder,  # {"error":"Invalid price","success":false}
                      'Size too small': InvalidOrder,  # {"error":"Size too small","success":false}
                      'Missing parameter price': InvalidOrder,  # {"error":"Missing parameter price","success":false}
                      'Order not found': OrderNotFound,  # {"error":"Order not found","success":false}
                  },
                  'broad': {
                      'Invalid parameter': BadRequest,  # {"error":"Invalid parameter start_time","success":false}
                      'The requested URL was not found on the server': BadRequest,
                      'No such coin': BadRequest,
                      'No such market': BadRequest,
                      'An unexpected error occurred': ExchangeError,  # {"error":"An unexpected error occurred, please try again later(58BC21C795).","success":false}
                  },
              },
              'precisionMode': DECIMAL_PLACES,
          })
  
      def fetch_markets(self, params={}):
          response = self.publicGetStatsTickerJson(params)
          result = []
          ids = list(response.keys())
          for i in range(0, len(ids)):
              id = ids[i]
              baseId, quoteId = id.split('_')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = (base + '/' + quote)
              precision = {
                  'price': None,
                  'amount': None,
              }
              info = {}
              info[id] = self.safe_value(response, id)
              entry = {
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'active': True,
                  'precision': precision,
                  'limits': None,
                  'info': info,
              }
              result.append(entry)
          return result
  
      def fetch_currencies(self, params={}):
          if not self.apiKey or not self.uid:
              raise AuthenticationError(self.id + " fetchCurrencies is an authenticated endpoint, therefore it requires 'apiKey' and 'uid' credentials. If you don't need currency details, set exchange.has['fetchCurrencies'] = False before calling its methods.")
          request = {
              'method': 'account',
              'action': 'getwalletsstatus',
          }
          response = self.privateGet(self.extend(request, params))
          ids = list(response.keys())
          result = {}
          for i in range(0, len(ids)):
              id = ids[i]
              if id == 'success':
                  continue
              currency = response[id]
              code = self.safe_currency_code(id)
              result[code] = {
                  'id': id,
                  'code': code,
                  'info': currency,
                  'name': None,
                  'active': self.safe_value(currency, 'is_online'),
                  'fee': self.safe_float(currency, 'current_optimal_fee'),
                  'precision': self.safe_integer(currency, 'decimal_point'),
                  'limits': {
                      'amount': {
                          'min': None,
                          'max': None,
                      },
                      'price': {
                          'min': None,
                          'max': None,
                      },
                      'cost': {
                          'min': None,
                          'max': None,
                      },
                      'withdraw': {
                          'min': self.safe_float(currency, 'current_minimal_amount'),
                          'max': None,
                      },
                  },
              }
          return result
  
      def fetch_tickers(self, symbols=None, params={}):
          self.load_markets()
          symbols = self.symbols if (symbols is None) else symbols
          tickers = self.publicGetStatsTickerJson(params)
          marketIds = list(self.marketsById.keys())
          result = {}
          for i in range(0, len(marketIds)):
              marketId = marketIds[i]
              market = self.marketsById[marketId]
              symbol = market['symbol']
              ticker = self.safe_value(tickers, marketId)
              if self.in_array(symbol, symbols):
                  result[symbol] = self.parse_ticker(ticker, market)
          return result
  
      def fetch_ticker(self, symbol, params={}):
          ticker = self.fetch_tickers([symbol])
          return self.safe_value(ticker, symbol)
  
      def parse_ticker(self, ticker, market):
          timestamp = self.milliseconds()
          symbol = market['symbol']
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': self.safe_float(ticker, 'max24H'),
              'low': self.safe_float(ticker, 'min24H'),
              'bid': self.safe_float(ticker, 'bid'),
              'bidVolume': None,
              'ask': self.safe_float(ticker, 'ask'),
              'askVolume': None,
              'vwap': None,
              'open': None,
              'close': self.safe_float(ticker, 'last'),
              'last': self.safe_float(ticker, 'last'),
              'previousClose': None,
              'change': None,
              'percentage': None,
              'average': None,
              'baseVolume': None,
              'quoteVolume': None,
              'info': ticker,
          }
  
      def fetch_order_book(self, symbol, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          baseId, quoteId = market['id'].split('_')
          request = {
              'base': baseId,
              'quote': quoteId,
          }
          response = self.publicGetStatsOrderbookBaseQuoteJson(self.extend(request, params))
          data = self.safe_value(response, 'data')
          timestamp = self.safe_timestamp(data, 'timestamp')
          parsedOrderBook = self.parse_order_book(response, timestamp, 'bids', 'asks', 1, 0)
          if limit is not None:
              parsedOrderBook['bids'] = self.filter_by_since_limit(parsedOrderBook['bids'], None, limit)
              parsedOrderBook['asks'] = self.filter_by_since_limit(parsedOrderBook['asks'], None, limit)
          return parsedOrderBook
  
      def fetch_trades(self, symbol, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'base': market['baseId'],
              'quote': market['quoteId'],
          }
          response = self.publicGetStatsHistoryBaseQuoteJson(self.extend(request, params))
          trades = self.safe_value(response, 'history')
          return self.parse_trades(trades, market, since, limit)
  
      def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          request = {
              'method': 'account',
              'action': 'history',
          }
          response = self.privateGet(self.extend(request, params))
          trades = self.safe_value(response, 'history', [])
          return self.parse_trades(trades, market, since, limit)
  
      def parse_trade(self, trade, market=None):
          #  fetchTrades
          #
          #    {
          #         "time":1531917229,
          #         "nr":"786",
          #         "amount":"0.00018620",
          #         "price":"7314.57",
          #         "type":"a"
          #    }
          #
          #  fetchMyTrades
          #
          #    {
          #         "currency1": "btc",
          #         "currency2": "usd",
          #         "amount": "0.00100000",
          #         "time_close": 1516212758,
          #         "price": "4.00",
          #         "fee_taker": "50",  # Idk what does it exactly means
          #         "fee_maker": "0",
          #         "type": "bid",
          #         "action": "open"
          #    }
          id = self.safe_string(trade, 'nr')
          timestamp = self.safe_integer_2(trade, 'time', 'time_close')
          if 'time' in trade:
              # API return timestamp in different formats depending on endpoint. Of course self isn't specified in docs xD
              timestamp = timestamp * 1000
          type = None
          baseId = self.safe_string(trade, 'currency1')
          quoteId = self.safe_string(trade, 'currency2')
          symbol = None
          quote = None
          if baseId is not None and quoteId is not None:
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = (base + '/' + quote)
          else:
              symbol = market['symbol']
              quote = market['quote']
          side = self.safe_string(trade, 'type')
          if side == 'a' or side == 'ask':
              side = 'sell'
          elif side == 'b' or side == 'bid':
              side = 'buy'
          price = self.safe_float(trade, 'price')
          amount = self.safe_float(trade, 'amount')
          cost = None
          if price is not None:
              if amount is not None:
                  cost = price * amount
                  if self.currency(quote)['precision'] is not None:
                      cost = self.currency_to_precision(quote, cost)
          fee = None  # todo
          return {
              'id': id,
              'info': trade,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'type': type,
              'order': None,
              'side': side,
              'takerOrMaker': None,
              'price': price,
              'amount': amount,
              'cost': cost,
              'fee': fee,
          }
  
      def fetch_balance(self, params={}):
          self.load_markets()
          request = {
              'method': 'account',
              'action': 'info',
          }
          response = self.privateGet(self.extend(request, params))
          result = {
              'info': response,
          }
          balances = self.safe_value(response, 'balances', [])
          currencies = list(balances.keys())
          for i in range(0, len(currencies)):
              balance = self.safe_value(balances, currencies[i])
              currencyCode = self.safe_currency_code(currencies[i])
              account = self.account()
              account['free'] = self.safe_float(balance, 'active')
              account['used'] = self.safe_float(balance, 'inactive')
              result[currencyCode] = account
          return self.parse_balance(result)
  
      def create_order(self, symbol, type, side, amount, price=None, params={}):
          self.load_markets()
          market = self.market(symbol)
          orderId = None
          response = None
          feeCost = None
          feeCurrency = None
          if type == 'limit':
              request = {
                  'method': 'transactions',
                  'action': side,
                  'market1': market['baseId'],
                  'market2': market['quoteId'],
                  'amount': self.currency_to_precision(market['base'], amount),
                  'rate': self.currency_to_precision(market['quote'], price),
              }
              response = self.privateGet(self.extend(request, params))
              order = self.safe_value(response, 'actions')
              orderId = self.safe_string(order, 'order')
          elif type == 'market':
              request = {
                  'method': 'account',
                  'action': 'convert',
              }
              request['market1'] = market['baseId'] if (side == 'sell') else market['quoteId']
              request['market2'] = market['quoteId'] if (side == 'sell') else market['baseId']
              currencyOfAmount = market['base'] if (side == 'sell') else market['quote']
              request['amount'] = self.currency_to_precision(currencyOfAmount, amount)
              response = self.privateGet(self.extend(request, params))
              feeCurrency = market['quote'] if (side == 'sell') else market['base']
              feeCost = self.safe_string(response, 'fee')
          timestamp = self.milliseconds()
          return {
              'id': orderId,
              'clientOrderId': None,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': None,
              'status': 'open',
              'symbol': market['symbol'],
              'type': type,
              'side': side,
              'price': price,
              'amount': amount,
              'filled': None,
              'remaining': None,
              'cost': None,
              'fee': {
                  'currency': feeCurrency,
                  'cost': feeCost,
                  'rate': None,
              },
              'trades': None,
              'info': response,
          }
  
      def fetch_open_orders(self, symbol=None, since=None, limit=None, params={}):
          self.load_markets()
          request = {
              'method': 'account',
              'action': 'activeoffers',
          }
          response = self.privateGet(self.extend(request, params))
          result = self.safe_value(response, 'offers', [])
          orders = self.parse_orders(result, None, since, limit)
          if symbol is not None:
              orders = self.filter_by(orders, 'symbol', symbol)
          return orders
  
      def parse_order(self, order, market=None):
          # due to very diverse structure of orders self method only work for these returned by fetchOpenOrders
          status = 'open'
          side = self.safe_string(order, 'offertype')
          if side == 'ask':
              side = 'sell'
          elif side == 'bid':
              side = 'buy'
          symbol = None
          if market is None:
              baseId = self.safe_string(order, 'currency1')
              quoteId = self.safe_string(order, 'currency2')
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = (base + '/' + quote)
          else:
              symbol = market['symbol']
          timestamp = self.safe_integer(order, 'time_open')
          return {
              'info': order,
              'id': self.safe_string(order, 'nr'),
              'clientOrderId': None,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'lastTradeTimestamp': None,
              'symbol': symbol,
              'type': None,
              'side': side,
              'price': self.safe_float(order, 'price'),
              'amount': self.safe_float(order, 'amount'),
              'remaining': None,
              'filled': None,
              'status': status,
              'fee': None,
              'cost': None,
              'trades': None,
          }
  
      def cancel_order(self, id, symbol=None, params={}):
          side_in_params = ('side' in params)
          if not side_in_params:
              raise ArgumentsRequired(self.id + ' cancelOrder requires a `side` parameter(sell or buy)')
          side = 'bid' if (params['side'] == 'buy') else 'ask'  # Typo could cause cancel wrong order. todo: handle typo
          params = self.omit(params, ['side', 'currency'])
          request = {
              'method': 'transactions',
              'action': 'cancel',
              'order': int(id),
              'typ': side,
          }
          return self.privateGet(self.extend(request, params))
  
      def cancel_unified_order(self, order, params={}):
          # https://github.com/ccxt/ccxt/issues/6838
          request = {
              'side': order['side'],
          }
          return self.cancel_order(order['id'], None, self.extend(request, params))
  
      def create_deposit_address(self, code, params={}):
          # not yet documented exchange api method
          self.load_markets()
          currencyId = self.currency_id(code)
          request = {
              'method': 'account',
              'action': 'newaddress',
              'currency': currencyId,
          }
          response = self.privateGet(self.extend(request, params))
          address = self.safe_string(response, 'address')
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'info': response,
          }
  
      def fetch_deposit_address(self, code, params={}):
          self.load_markets()
          currencyId = self.currency_id(code)
          currencyId = currencyId.upper()
          request = {
              'method': 'account',
              'action': 'info',
          }
          response = self.privateGet(self.extend(request, params))
          deposits = self.safe_value(response, 'deposit')
          deposit = self.safe_value(deposits, currencyId)
          address = self.safe_string(deposit, 'deposit')
          self.check_address(address)
          return {
              'currency': code,
              'address': address,
              'info': response,
          }
  
      def fetch_deposits(self, code=None, since=None, limit=None, params={}):
          if code is None:
              raise ArgumentsRequired(self.id + ' fetchDeposits requires a currency code argument')
          self.load_markets()
          currency = self.currency(code)
          currencyId = currency['id']
          request = {
              'method': 'account',
              'action': 'deposits',
              'currency': currencyId,
          }
          response = self.privateGet(self.extend(request, params))
          transactions = self.safe_value(response, 'history', [])
          return self.parse_transactions(transactions, currency)
  
      def fetch_withdrawals(self, code=None, since=None, limit=None, params={}):
          if code is None:
              raise ArgumentsRequired(self.id + ' fetchDeposits requires a currency code argument')
          self.load_markets()
          currency = self.currency(code)
          currencyId = currency['id']
          request = {
              'method': 'account',
              'action': 'withdrawals',
              'currency': currencyId,
          }
          response = self.privateGet(self.extend(request, params))
          transactions = self.safe_value(response, 'history', [])
          return self.parse_transactions(transactions, currency)
  
      def parse_transaction(self, transaction, currency=None):
          #
          # fetchDeposits
          #
          #     {
          #       "time": "1530883428",
          #       "amount": "0.13750000",
          #       "type": "b787400027b4eae298bad72150384540a23342daaa3eec1c8d17459c103c6bbc",
          #       "state": "1"
          #     }
          #
          # fetchWithdrawals
          #
          #     {
          #         "time": "1528715035",
          #         "amount": "1.00000000",
          #         "tx": "01b8ae6437843879574b69daf95542aff43a4aefaa90e8f70ebf572eccf01cad",
          #         "address": "2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF",
          #         "state": "0"
          #     },
          #
          timestamp = self.safe_integer(transaction, 'time')
          currencyCode = self.safe_string(currency, 'code')
          amount = self.safe_float(transaction, 'amount')
          address = self.safe_string(transaction, 'address')
          status = self.safe_string(transaction, 'state')  # todo: ask support
          txid = self.safe_string_2(transaction, 'type', 'tx')
          return {
              'info': transaction,
              'id': None,
              'currency': currencyCode,
              'amount': amount,
              'address': address,
              'tag': None,
              'status': status,
              'type': None,
              'updated': None,
              'txid': txid,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'fee': None,
          }
  
      def fetch_trading_fees(self, params={}):
          self.load_markets()
          request = {
              'method': 'account',
              'action': 'info',
          }
          response = self.privateGet(self.extend(request, params))
          account = self.safe_value(response, 'account')
          fees = self.safe_value(account, 'fee')
          return {
              'info': response,
              'maker': self.safe_float(fees, 'maker'),
              'taker': self.safe_float(fees, 'taker'),
          }
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          request = '/' + self.implode_params(path, params)
          url = self.urls['api'][api] + request
          if api == 'private':
              self.check_required_credentials()
              params['id'] = self.uid
              params['key'] = self.apiKey
          if params:
              url += '?' + self.urlencode(params)
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  