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.async_support.bitfinex import bitfinex
  import hashlib
  import math
  from ccxt.base.errors import ExchangeError
  from ccxt.base.errors import InsufficientFunds
  from ccxt.base.errors import NotSupported
  
  
  class bitfinex2(bitfinex):
  
      def describe(self):
          return self.deep_extend(super(bitfinex2, self).describe(), {
              'id': 'bitfinex2',
              'name': 'Bitfinex',
              'countries': ['VG'],
              'version': 'v2',
              'certified': False,
              # new metainfo interface
              'has': {
                  'CORS': True,
                  'createLimitOrder': False,
                  'createMarketOrder': False,
                  'createOrder': False,
                  'deposit': False,
                  'editOrder': False,
                  'fetchDepositAddress': False,
                  'fetchClosedOrders': False,
                  'fetchFundingFees': False,
                  'fetchMyTrades': True,
                  'fetchOHLCV': True,
                  'fetchOpenOrders': False,
                  'fetchOrder': True,
                  'fetchTickers': True,
                  'fetchTradingFee': False,
                  'fetchTradingFees': False,
                  'withdraw': True,
              },
              'timeframes': {
                  '1m': '1m',
                  '5m': '5m',
                  '15m': '15m',
                  '30m': '30m',
                  '1h': '1h',
                  '3h': '3h',
                  '6h': '6h',
                  '12h': '12h',
                  '1d': '1D',
                  '1w': '7D',
                  '2w': '14D',
                  '1M': '1M',
              },
              'rateLimit': 1500,
              'urls': {
                  'logo': 'https://user-images.githubusercontent.com/1294454/27766244-e328a50c-5ed2-11e7-947b-041416579bb3.jpg',
                  'api': {
                      'v1': 'https://api.bitfinex.com',
                      'public': 'https://api-pub.bitfinex.com',
                      'private': 'https://api.bitfinex.com',
                  },
                  'www': 'https://www.bitfinex.com',
                  'doc': [
                      'https://docs.bitfinex.com/v2/docs/',
                      'https://github.com/bitfinexcom/bitfinex-api-node',
                  ],
                  'fees': 'https://www.bitfinex.com/fees',
              },
              'api': {
                  'v1': {
                      'get': [
                          'symbols',
                          'symbols_details',
                      ],
                  },
                  'public': {
                      'get': [
                          'conf/pub:map:currency:label',
                          'platform/status',
                          'tickers',
                          'ticker/{symbol}',
                          'trades/{symbol}/hist',
                          'book/{symbol}/{precision}',
                          'book/{symbol}/P0',
                          'book/{symbol}/P1',
                          'book/{symbol}/P2',
                          'book/{symbol}/P3',
                          'book/{symbol}/R0',
                          'stats1/{key}:{size}:{symbol}:{side}/{section}',
                          'stats1/{key}:{size}:{symbol}/{section}',
                          'stats1/{key}:{size}:{symbol}:long/last',
                          'stats1/{key}:{size}:{symbol}:long/hist',
                          'stats1/{key}:{size}:{symbol}:short/last',
                          'stats1/{key}:{size}:{symbol}:short/hist',
                          'candles/trade:{timeframe}:{symbol}/{section}',
                          'candles/trade:{timeframe}:{symbol}/last',
                          'candles/trade:{timeframe}:{symbol}/hist',
                      ],
                      'post': [
                          'calc/trade/avg',
                          'calc/fx',
                      ],
                  },
                  'private': {
                      'post': [
                          'auth/r/wallets',
                          'auth/r/orders/{symbol}',
                          'auth/r/orders/{symbol}/new',
                          'auth/r/orders/{symbol}/hist',
                          'auth/r/order/{symbol}:{id}/trades',
                          'auth/w/order/submit',
                          'auth/r/trades/hist',
                          'auth/r/trades/{symbol}/hist',
                          'auth/r/positions',
                          'auth/r/positions/hist',
                          'auth/r/positions/audit',
                          'auth/r/funding/offers/{symbol}',
                          'auth/r/funding/offers/{symbol}/hist',
                          'auth/r/funding/loans/{symbol}',
                          'auth/r/funding/loans/{symbol}/hist',
                          'auth/r/funding/credits/{symbol}',
                          'auth/r/funding/credits/{symbol}/hist',
                          'auth/r/funding/trades/{symbol}/hist',
                          'auth/r/info/margin/{key}',
                          'auth/r/info/funding/{key}',
                          'auth/r/ledgers/hist',
                          'auth/r/movements/hist',
                          'auth/r/movements/{currency}/hist',
                          'auth/r/stats/perf:{timeframe}/hist',
                          'auth/r/alerts',
                          'auth/w/alert/set',
                          'auth/w/alert/{type}:{symbol}:{price}/del',
                          'auth/calc/order/avail',
                          'auth/r/ledgers/{symbol}/hist',
                          'auth/r/settings',
                          'auth/w/settings/set',
                          'auth/w/settings/del',
                          'auth/r/info/user',
                      ],
                  },
              },
              'fees': {
                  'trading': {
                      'maker': 0.1 / 100,
                      'taker': 0.2 / 100,
                  },
                  'funding': {
                      'withdraw': {
                          'BTC': 0.0004,
                          'BCH': 0.0001,
                          'ETH': 0.00135,
                          'EOS': 0.0,
                          'LTC': 0.001,
                          'OMG': 0.15097,
                          'IOT': 0.0,
                          'NEO': 0.0,
                          'ETC': 0.01,
                          'XRP': 0.02,
                          'ETP': 0.01,
                          'ZEC': 0.001,
                          'BTG': 0.0,
                          'DASH': 0.01,
                          'XMR': 0.0001,
                          'QTM': 0.01,
                          'EDO': 0.23687,
                          'DAT': 9.8858,
                          'AVT': 1.1251,
                          'SAN': 0.35977,
                          'USDT': 5.0,
                          'SPK': 16.971,
                          'BAT': 1.1209,
                          'GNT': 2.8789,
                          'SNT': 9.0848,
                          'QASH': 1.726,
                          'YYW': 7.9464,
                      },
                  },
              },
              'options': {
                  'precision': 'R0',  # P0, P1, P2, P3, P4, R0
                  'orderTypes': {
                      'MARKET': None,
                      'EXCHANGE MARKET': 'market',
                      'LIMIT': None,
                      'EXCHANGE LIMIT': 'limit',
                      'STOP': None,
                      'EXCHANGE STOP': 'stopOrLoss',
                      'TRAILING STOP': None,
                      'EXCHANGE TRAILING STOP': None,
                      'FOK': None,
                      'EXCHANGE FOK': 'limit FOK',
                      'STOP LIMIT': None,
                      'EXCHANGE STOP LIMIT': 'limit stop',
                      'IOC': None,
                      'EXCHANGE IOC': 'limit ioc',
                  },
                  'fiat': {
                      'USD': 'USD',
                      'EUR': 'EUR',
                      'JPY': 'JPY',
                      'GBP': 'GBP',
                  },
              },
          })
  
      def is_fiat(self, code):
          return(code in self.options['fiat'])
  
      def get_currency_id(self, code):
          return 'f' + code
  
      async def fetch_markets(self, params={}):
          response = await self.v1GetSymbolsDetails(params)
          result = []
          for i in range(0, len(response)):
              market = response[i]
              id = self.safe_string(market, 'pair')
              id = id.upper()
              baseId = None
              quoteId = None
              if id.find(':') >= 0:
                  parts = id.split(':')
                  baseId = parts[0]
                  quoteId = parts[1]
              else:
                  baseId = id[0:3]
                  quoteId = id[3:6]
              base = self.safe_currency_code(baseId)
              quote = self.safe_currency_code(quoteId)
              symbol = base + '/' + quote
              id = 't' + id
              baseId = self.get_currency_id(baseId)
              quoteId = self.get_currency_id(quoteId)
              precision = {
                  'price': self.safe_integer(market, 'price_precision'),
                  'amount': self.safe_integer(market, 'price_precision'),
              }
              limits = {
                  'amount': {
                      'min': self.safe_float(market, 'minimum_order_size'),
                      'max': self.safe_float(market, 'maximum_order_size'),
                  },
                  'price': {
                      'min': math.pow(10, -precision['price']),
                      'max': math.pow(10, precision['price']),
                  },
              }
              limits['cost'] = {
                  'min': limits['amount']['min'] * limits['price']['min'],
                  'max': None,
              }
              result.append({
                  'id': id,
                  'symbol': symbol,
                  'base': base,
                  'quote': quote,
                  'baseId': baseId,
                  'quoteId': quoteId,
                  'active': True,
                  'precision': precision,
                  'limits': limits,
                  'info': market,
                  'swap': False,
                  'spot': False,
                  'futures': False,
              })
          return result
  
      async def fetch_balance(self, params={}):
          # self api call does not return the 'used' amount - use the v1 version instead(which also returns zero balances)
          await self.load_markets()
          response = await self.privatePostAuthRWallets(params)
          balanceType = self.safe_string(params, 'type', 'exchange')
          result = {'info': response}
          for b in range(0, len(response)):
              balance = response[b]
              accountType = balance[0]
              currency = balance[1]
              total = balance[2]
              available = balance[4]
              if accountType == balanceType:
                  if currency[0] == 't':
                      currency = currency[1:]
                  code = self.safe_currency_code(currency)
                  account = self.account()
                  # do not fill in zeroes and missing values in the parser
                  # rewrite and unify the following to use the unified parseBalance
                  account['total'] = total
                  if not available:
                      if available == 0:
                          account['free'] = 0
                          account['used'] = total
                      else:
                          account['free'] = total
                  else:
                      account['free'] = available
                      account['used'] = account['total'] - account['free']
                  result[code] = account
          return self.parse_balance(result)
  
      async def fetch_order_book(self, symbol, limit=None, params={}):
          await self.load_markets()
          precision = self.safe_value(self.options, 'precision', 'R0')
          request = {
              'symbol': self.market_id(symbol),
              'precision': precision,
          }
          if limit is not None:
              request['len'] = limit  # 25 or 100
          fullRequest = self.extend(request, params)
          orderbook = await self.publicGetBookSymbolPrecision(fullRequest)
          timestamp = self.milliseconds()
          result = {
              'bids': [],
              'asks': [],
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'nonce': None,
          }
          priceIndex = 1 if (fullRequest['precision'] == 'R0') else 0
          for i in range(0, len(orderbook)):
              order = orderbook[i]
              price = order[priceIndex]
              amount = abs(order[2])
              side = 'bids' if (order[2] > 0) else 'asks'
              result[side].append([price, amount])
          result['bids'] = self.sort_by(result['bids'], 0, True)
          result['asks'] = self.sort_by(result['asks'], 0)
          return result
  
      def parse_ticker(self, ticker, market=None):
          timestamp = self.milliseconds()
          symbol = None
          if market is not None:
              symbol = market['symbol']
          length = len(ticker)
          last = ticker[length - 4]
          return {
              'symbol': symbol,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'high': ticker[length - 2],
              'low': ticker[length - 1],
              'bid': ticker[length - 10],
              'bidVolume': None,
              'ask': ticker[length - 8],
              'askVolume': None,
              'vwap': None,
              'open': None,
              'close': last,
              'last': last,
              'previousClose': None,
              'change': ticker[length - 6],
              'percentage': ticker[length - 5] * 100,
              'average': None,
              'baseVolume': ticker[length - 3],
              'quoteVolume': None,
              'info': ticker,
          }
  
      async def fetch_tickers(self, symbols=None, params={}):
          await self.load_markets()
          request = {}
          if symbols is not None:
              ids = self.market_ids(symbols)
              request['symbols'] = ','.join(ids)
          else:
              request['symbols'] = 'ALL'
          tickers = await self.publicGetTickers(self.extend(request, params))
          result = {}
          for i in range(0, len(tickers)):
              ticker = tickers[i]
              id = ticker[0]
              if id in self.markets_by_id:
                  market = self.markets_by_id[id]
                  symbol = market['symbol']
                  result[symbol] = self.parse_ticker(ticker, market)
          return result
  
      async def fetch_ticker(self, symbol, params={}):
          await self.load_markets()
          market = self.market(symbol)
          request = {
              'symbol': market['id'],
          }
          ticker = await self.publicGetTickerSymbol(self.extend(request, params))
          return self.parse_ticker(ticker, market)
  
      def parse_trade(self, trade, market=None):
          #
          # fetchTrades(public)
          #
          #     [
          #         ID,
          #         MTS,  # timestamp
          #         AMOUNT,
          #         PRICE
          #     ]
          #
          # fetchMyTrades(private)
          #
          #     [
          #         ID,
          #         PAIR,
          #         MTS_CREATE,
          #         ORDER_ID,
          #         EXEC_AMOUNT,
          #         EXEC_PRICE,
          #         ORDER_TYPE,
          #         ORDER_PRICE,
          #         MAKER,
          #         FEE,
          #         FEE_CURRENCY,
          #         ...
          #     ]
          #
          tradeLength = len(trade)
          isPrivate = (tradeLength > 5)
          id = str(trade[0])
          amountIndex = 4 if isPrivate else 2
          amount = trade[amountIndex]
          cost = None
          priceIndex = 5 if isPrivate else 3
          price = trade[priceIndex]
          side = None
          orderId = None
          takerOrMaker = None
          type = None
          fee = None
          symbol = None
          timestampIndex = 2 if isPrivate else 1
          timestamp = trade[timestampIndex]
          if isPrivate:
              marketId = trade[1]
              if marketId is not None:
                  if marketId in self.markets_by_id:
                      market = self.markets_by_id[marketId]
                      symbol = market['symbol']
                  else:
                      symbol = marketId
              orderId = str(trade[3])
              takerOrMaker = 'maker' if (trade[8] == 1) else 'taker'
              feeCost = trade[9]
              feeCurrency = self.safe_currency_code(trade[10])
              if feeCost is not None:
                  fee = {
                      'cost': abs(feeCost),
                      'currency': feeCurrency,
                  }
              orderType = trade[6]
              type = self.safe_string(self.options['orderTypes'], orderType)
          if symbol is None:
              if market is not None:
                  symbol = market['symbol']
          if amount is not None:
              side = 'sell' if (amount < 0) else 'buy'
              amount = abs(amount)
              if cost is None:
                  if price is not None:
                      cost = amount * price
          return {
              'id': id,
              'timestamp': timestamp,
              'datetime': self.iso8601(timestamp),
              'symbol': symbol,
              'order': orderId,
              'side': side,
              'type': type,
              'takerOrMaker': takerOrMaker,
              'price': price,
              'amount': amount,
              'cost': cost,
              'fee': fee,
              'info': trade,
          }
  
      async def fetch_trades(self, symbol, since=None, limit=None, params={}):
          await self.load_markets()
          market = self.market(symbol)
          sort = '-1'
          request = {
              'symbol': market['id'],
          }
          if since is not None:
              request['start'] = since
              sort = '1'
          if limit is not None:
              request['limit'] = limit  # default 120, max 5000
          request['sort'] = sort
          response = await self.publicGetTradesSymbolHist(self.extend(request, params))
          #
          #     [
          #         [
          #             ID,
          #             MTS,  # timestamp
          #             AMOUNT,
          #             PRICE
          #         ]
          #     ]
          #
          trades = self.sort_by(response, 1)
          return self.parse_trades(trades, market, None, limit)
  
      async def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=100, params={}):
          await self.load_markets()
          market = self.market(symbol)
          if limit is None:
              limit = 100  # default 100, max 5000
          if since is None:
              since = self.milliseconds() - self.parse_timeframe(timeframe) * limit * 1000
          request = {
              'symbol': market['id'],
              'timeframe': self.timeframes[timeframe],
              'sort': 1,
              'start': since,
              'limit': limit,
          }
          response = await self.publicGetCandlesTradeTimeframeSymbolHist(self.extend(request, params))
          return self.parse_ohlcvs(response, market, timeframe, since, limit)
  
      async def create_order(self, symbol, type, side, amount, price=None, params={}):
          raise NotSupported(self.id + ' createOrder not implemented yet')
  
      def cancel_order(self, id, symbol=None, params={}):
          raise NotSupported(self.id + ' cancelOrder not implemented yet')
  
      async def fetch_order(self, id, symbol=None, params={}):
          raise NotSupported(self.id + ' fetchOrder not implemented yet')
  
      async def fetch_deposit_address(self, currency, params={}):
          raise NotSupported(self.id + ' fetchDepositAddress() not implemented yet.')
  
      async def withdraw(self, code, amount, address, tag=None, params={}):
          raise NotSupported(self.id + ' withdraw not implemented yet')
  
      async def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}):
          await self.load_markets()
          market = None
          request = {
              'end': self.milliseconds(),
          }
          if since is not None:
              request['start'] = since
          if limit is not None:
              request['limit'] = limit  # default 25, max 1000
          method = 'privatePostAuthRTradesHist'
          if symbol is not None:
              market = self.market(symbol)
              request['symbol'] = market['id']
              method = 'privatePostAuthRTradesSymbolHist'
          response = await getattr(self, method)(self.extend(request, params))
          return self.parse_trades(response, market, since, limit)
  
      def nonce(self):
          return self.milliseconds()
  
      def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
          request = '/' + self.implode_params(path, params)
          query = self.omit(params, self.extract_params(path))
          if api == 'v1':
              request = api + request
          else:
              request = self.version + request
          url = self.urls['api'][api] + '/' + request
          if api == 'public':
              if query:
                  url += '?' + self.urlencode(query)
          if api == 'private':
              self.check_required_credentials()
              nonce = str(self.nonce())
              body = self.json(query)
              auth = '/api/' + request + nonce + body
              signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha384)
              headers = {
                  'bfx-nonce': nonce,
                  'bfx-apikey': self.apiKey,
                  'bfx-signature': signature,
                  'Content-Type': 'application/json',
              }
          return {'url': url, 'method': method, 'body': body, 'headers': headers}
  
      async def request(self, path, api='public', method='GET', params={}, headers=None, body=None):
          response = await self.fetch2(path, api, method, params, headers, body)
          if response:
              if 'message' in response:
                  if response['message'].find('not enough exchange balance') >= 0:
                      raise InsufficientFunds(self.id + ' ' + self.json(response))
                  raise ExchangeError(self.id + ' ' + self.json(response))
              return response
          elif response == '':
              raise ExchangeError(self.id + ' returned empty response')
          return response
  