def fetch_trades(self, symbol, since=None, limit=None, params={}): if symbol != 'BTC/JPY': raise NotSupported(self.id + ' fetchTrades() supports BTC/JPY only') market = self.market(symbol) response = self.publicGetTrades(params) return self.parse_trades(response, market)
async def fetch_deposit_address(self, code=None, since=None, limit=None, params={}): raise NotSupported('fetch_deposit_address() is not supported yet')
async def fetch_trading_fees(self, params={}): raise NotSupported('fetch_trading_fees() not supported yet')
async def cancel_order(self, id, symbol=None, params={}): raise NotSupported('cancel_order() not supported yet')
async def fetch_transactions(self, code=None, since=None, limit=None, params={}): raise NotSupported('fetch_transactions() is not supported yet')
async def fetch_deposits(self, symbol=None, since=None, limit=None, params={}): raise NotSupported('fetch_deposits() is not supported yet')
async def create_order(self, symbol, type, side, amount, price=None, params={}): raise NotSupported('create_order() not supported yet')
async def fetch_markets_from_web(self, params={}): response = await self.webGetRestApi(params) sections = response.split( '<h1 id="symbols-and-minimums">Symbols and minimums</h1>') numSections = len(sections) error = self.id + ' the ' + self.name + ' API doc HTML markup has changed, breaking the parser of order limits and precision info for ' + self.name + ' markets.' if numSections != 2: raise NotSupported(error) tables = sections[1].split('tbody>') numTables = len(tables) if numTables < 2: raise NotSupported(error) rows = tables[1].split("\n<tr>\n") # eslint-disable-line quotes numRows = len(rows) if numRows < 2: raise NotSupported(error) result = [] # skip the first element(empty string) for i in range(1, numRows): row = rows[i] cells = row.split("</td>\n") # eslint-disable-line quotes numCells = len(cells) if numCells < 5: raise NotSupported(error) # [ # '<td>btcusd', # currency # '<td>0.00001 BTC(1e-5)', # min order size # '<td>0.00000001 BTC(1e-8)', # tick size # '<td>0.01 USD', # quote currency price increment # '</tr>' # ] marketId = cells[0].replace('<td>', '') # base = self.safe_currency_code(baseId) minAmountString = cells[1].replace('<td>', '') minAmountParts = minAmountString.split(' ') minAmount = self.safe_number(minAmountParts, 0) amountPrecisionString = cells[2].replace('<td>', '') amountPrecisionParts = amountPrecisionString.split(' ') amountPrecision = self.safe_number(amountPrecisionParts, 0) idLength = len(marketId) - 0 startingIndex = idLength - 3 quoteId = marketId[startingIndex:idLength] quote = self.safe_currency_code(quoteId) pricePrecisionString = cells[3].replace('<td>', '') pricePrecisionParts = pricePrecisionString.split(' ') pricePrecision = self.safe_number(pricePrecisionParts, 0) baseId = marketId.replace(quoteId, '') base = self.safe_currency_code(baseId) symbol = base + '/' + quote active = None result.append({ 'id': marketId, 'info': row, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'type': 'spot', 'spot': True, 'active': active, 'precision': { 'amount': amountPrecision, 'price': pricePrecision, }, 'limits': { 'amount': { 'min': minAmount, 'max': None, }, 'price': { 'min': None, 'max': None, }, 'cost': { 'min': None, 'max': None, }, }, }) return result
def fetch_markets_from_web(self, symbols=None, params={}): response = self.webGetRestApi(params) sections = response.split( '<h1 id="symbols-and-minimums">Symbols and minimums</h1>') numSections = len(sections) error = self.id + ' the ' + self.name + ' API doc HTML markup has changed, breaking the parser of order limits and precision info for ' + self.name + ' markets.' if numSections != 2: raise NotSupported(error) tables = sections[1].split('tbody>') numTables = len(tables) if numTables < 2: raise NotSupported(error) # tables[1] = tables[1].replace("\n", '') # eslint-disable-line quotes rows = tables[1].split("<tr>\n") # eslint-disable-line quotes numRows = len(rows) if numRows < 2: raise NotSupported(error) result = [] # skip the first element(empty string) for i in range(1, numRows): row = rows[i] cells = row.split("</td>\n") # eslint-disable-line quotes numCells = len(cells) if numCells < 7: raise NotSupported(error) # # [ # '<td><code class="prettyprint">btcusd</code>', # '<td>USD', # quote # '<td>BTC', # base # '<td>0.00001 BTC(1e-5)', # min amount # '<td>0.00000001 BTC(1e-8)', # amount min tick size # '<td>0.01 USD', # price min tick size # '</tr>\n' # ] # id = cells[0].replace('<td>', '') id = id.replace('<code class="prettyprint">', '') id = id.replace('</code>', '') baseId = cells[2].replace('<td>', '') quoteId = cells[1].replace('<td>', '') minAmountAsString = cells[3].replace('<td>', '') amountTickSizeAsString = cells[4].replace('<td>', '') priceTickSizeAsString = cells[5].replace('<td>', '') minAmount = minAmountAsString.split(' ') amountPrecision = amountTickSizeAsString.split(' ') pricePrecision = priceTickSizeAsString.split(' ') baseId = baseId.lower() quoteId = quoteId.lower() base = self.safe_currency_code(baseId) quote = self.safe_currency_code(quoteId) symbol = base + '/' + quote precision = { 'amount': self.precision_from_string(amountPrecision[0]), 'price': self.precision_from_string(pricePrecision[0]), } active = None result.append({ 'id': id, 'info': row, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'active': active, 'precision': precision, 'limits': { 'amount': { 'min': float(minAmount[0]), 'max': None, }, 'price': { 'min': None, 'max': None, }, 'cost': { 'min': None, 'max': None, }, }, }) return result
def parse_order(self, order, market=None): zeroExOrder = self.safe_value(order, 'zeroExOrder') id = self.safe_string(order, 'orderHash') if (id is None) and(zeroExOrder is not None): id = self.safe_string(zeroExOrder, 'orderHash') side = self.safe_string(order, 'side') type = self.safe_string(order, 'type') # injected from outside timestamp = self.safe_integer(order, 'creationTimestamp') if timestamp != 'None': timestamp = int(timestamp / 1000) symbol = None baseId = self.safe_string(order, 'baseTokenAddress') quoteId = self.safe_string(order, 'quoteTokenAddress') marketId = None if baseId is not None and quoteId is not None: marketId = baseId + '/' + quoteId market = self.safe_value(self.markets_by_id, marketId, market) base = None if market is not None: symbol = market['symbol'] base = market['base'] baseDecimals = self.safe_integer(self.options['decimals'], base, 18) price = self.safe_float(order, 'price') filledAmount = self.fromWei(self.safe_string(order, 'filledAmount'), 'ether', baseDecimals) settledAmount = self.fromWei(self.safe_string(order, 'settledAmount'), 'ether', baseDecimals) confirmedAmount = self.fromWei(self.safe_string(order, 'confirmedAmount'), 'ether', baseDecimals) failedAmount = self.fromWei(self.safe_string(order, 'failedAmount'), 'ether', baseDecimals) deadAmount = self.fromWei(self.safe_string(order, 'deadAmount'), 'ether', baseDecimals) prunedAmount = self.fromWei(self.safe_string(order, 'prunedAmount'), 'ether', baseDecimals) amount = self.fromWei(self.safe_string(order, 'initialAmount'), 'ether', baseDecimals) filled = self.sum(filledAmount, settledAmount, confirmedAmount) remaining = None lastTradeTimestamp = None timeline = self.safe_value(order, 'timeline') trades = None status = None if timeline is not None: numEvents = len(timeline) if numEvents > 0: timelineEventsGroupedByAction = self.group_by(timeline, 'action') if 'error' in timelineEventsGroupedByAction: status = 'failed' if 'filled' in timelineEventsGroupedByAction: fillEvents = self.safe_value(timelineEventsGroupedByAction, 'filled') numFillEvents = len(fillEvents) lastTradeTimestamp = self.safe_integer(fillEvents[numFillEvents - 1], 'timestamp') lastTradeTimestamp = lastTradeTimestamp if (lastTradeTimestamp is not None) else lastTradeTimestamp trades = [] for i in range(0, numFillEvents): trade = self.parse_trade(self.extend(fillEvents[i], { 'price': price, }), market) trades.append(self.extend(trade, { 'order': id, 'type': type, 'side': side, })) cost = None if filled is not None: if remaining is None: if amount is not None: remaining = amount - filled if price is not None: cost = filled * price fee = None feeCost = self.safe_string(order, 'feeAmount') if feeCost is not None: feeOption = self.safe_string(order, 'feeOption') feeCurrency = None if feeOption == 'feeInNative': if market is not None: feeCurrency = market['base'] elif feeOption == 'feeInZRX': feeCurrency = 'ZRX' else: raise NotSupported(self.id + ' encountered an unsupported order fee option: ' + feeOption) feeDecimals = self.safe_integer(self.options['decimals'], feeCurrency, 18) fee = { 'cost': self.fromWei(feeCost, 'ether', feeDecimals), 'currency': feeCurrency, } amountPrecision = market['precision']['amount'] if market else 8 if remaining is not None: if status is None: status = 'open' rest = remaining - failedAmount - deadAmount - prunedAmount if rest < math.pow(10, -amountPrecision): status = 'canceled' if (filled < amount) else 'closed' result = { 'info': order, 'id': id, 'symbol': symbol, 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'lastTradeTimestamp': lastTradeTimestamp, 'type': type, 'side': side, 'price': price, 'cost': cost, 'amount': amount, 'remaining': remaining, 'filled': filled, 'status': status, 'fee': fee, 'trades': trades, } return result
async def withdraw(self, currency, amount, address, params={}): raise NotSupported(self.id + ' withdraw not implemented yet')
def create_order(self, symbol, type, side, amount, price=None, params={}): # https://docs.idex.io/#create-order self.check_required_credentials() self.load_markets() market = self.market(symbol) nonce = self.uuidv1() typeEnum = None priceString = None if type == 'limit': typeEnum = 1 priceString = self.price_to_precision(symbol, price) elif type == 'market': typeEnum = 0 amountEnum = 0 # base quantity if 'quoteOrderQuantity' in params: if type != 'market': raise NotSupported( self.id + ' quoteOrderQuantity is not supported for ' + type + ' orders, only supported for market orders') amountEnum = 1 amount = self.safe_float(params, 'quoteOrderQuantity') sideEnum = 0 if (side == 'buy') else 1 walletBytes = self.remove0x_prefix(self.walletAddress) orderVersion = 1 amountString = self.amount_to_precision(symbol, amount) # https://docs.idex.io/#time-in-force timeInForceEnums = { 'gtc': 0, 'ioc': 2, 'fok': 3, } defaultTimeInForce = self.safe_string(self.options, 'defaultTimeInForce', 'gtc') timeInForce = self.safe_string(params, 'timeInForce', defaultTimeInForce) timeInForceEnum = None if timeInForce in timeInForceEnums: timeInForceEnum = timeInForceEnums[timeInForce] else: allOptions = list(timeInForceEnums.keys()) asString = ', '.join(allOptions) raise BadRequest( self.id + ' ' + timeInForce + ' is not a valid timeInForce, please choose one of ' + asString) # https://docs.idex.io/#self-trade-prevention selfTradePreventionEnums = { 'dc': 0, 'co': 1, 'cn': 2, 'cb': 3, } defaultSelfTradePrevention = self.safe_string( self.options, 'defaultSelfTradePrevention', 'cn') selfTradePrevention = self.safe_string(params, 'selfTradePrevention', defaultSelfTradePrevention) selfTradePreventionEnum = None if selfTradePrevention in selfTradePreventionEnums: selfTradePreventionEnum = selfTradePreventionEnums[ selfTradePrevention] else: allOptions = list(selfTradePreventionEnums.keys()) asString = ', '.join(allOptions) raise BadRequest( self.id + ' ' + selfTradePrevention + ' is not a valid selfTradePrevention, please choose one of ' + asString) byteArray = [ self.number_to_be(orderVersion, 1), self.base16_to_binary(nonce), self.base16_to_binary(walletBytes), self.encode( market['id'] ), # TODO: refactor to remove either encode or stringToBinary self.number_to_be(typeEnum, 1), self.number_to_be(sideEnum, 1), self.encode(amountString), self.number_to_be(amountEnum, 1), ] if type == 'limit': encodedPrice = self.encode(priceString) byteArray.append(encodedPrice) clientOrderId = self.safe_string(params, 'clientOrderId') if clientOrderId is not None: byteArray.append(self.encode(clientOrderId)) after = [ self.number_to_be(timeInForceEnum, 1), self.number_to_be(selfTradePreventionEnum, 1), self.number_to_be(0, 8), # unused ] allBytes = self.array_concat(byteArray, after) binary = self.binary_concat_array(allBytes) hash = self.hash(binary, 'keccak', 'hex') signature = self.sign_message_string(hash, self.privateKey) request = { 'parameters': { 'nonce': nonce, 'market': market['id'], 'side': side, 'type': type, 'wallet': self.walletAddress, 'timeInForce': timeInForce, 'selfTradePrevention': selfTradePrevention, }, 'signature': signature, } if type == 'limit': request['parameters']['price'] = priceString if amountEnum == 0: request['parameters']['quantity'] = amountString else: request['parameters']['quoteOrderQuantity'] = amountString if clientOrderId is not None: request['parameters']['clientOrderId'] = clientOrderId # { # market: 'DIL-ETH', # orderId: '7cdc8e90-eb7d-11ea-9e60-4118569f6e63', # wallet: '0x0AB991497116f7F5532a4c2f4f7B1784488628e1', # time: 1598873478650, # status: 'filled', # type: 'limit', # side: 'buy', # originalQuantity: '0.40000000', # executedQuantity: '0.40000000', # cumulativeQuoteQuantity: '0.03962396', # price: '1.00000000', # fills: [ # { # fillId: '48582d10-b9bb-3c4b-94d3-e67537cf2472', # price: '0.09905990', # quantity: '0.40000000', # quoteQuantity: '0.03962396', # time: 1598873478650, # makerSide: 'sell', # sequence: 5053, # fee: '0.00080000', # feeAsset: 'DIL', # gas: '0.00857497', # liquidity: 'taker', # txStatus: 'pending' # } # ], # avgExecutionPrice: '0.09905990' # } # we don't use self.extend here because it is a signed endpoint response = self.privatePostOrders(request) return self.parse_order(response, market)
def fetch_order_book(self, symbol, limit=None, params={}): if symbol != 'BTC/JPY': raise NotSupported(self.id + ' fetchOrderBook() supports BTC/JPY only') orderbook = self.publicGetOrderBooks(params) return self.parse_order_book(orderbook)
def create_order(self, symbol, type, side, amount, price=None, params={}): raise NotSupported(self.id + ' createOrder not implemented yet')
def fetch_order(self, id, symbol=None, params={}): raise NotSupported(self.id + ' fetch_order() is not implemented yet')
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None): raise NotSupported(self.id + ' sign() pure method must be redefined in derived classes')
def fetch_my_trades(self, symbol=None, since=None, limit=None, params={}): raise NotSupported(self.id + ' fetch_my_trades() not implemented yet')
def fetch_bids_asks(self, symbols=None, params={}): raise NotSupported(self.id + ' API does not allow to fetch all prices at once with a single call to fetch_bid_asks() for now')
async def fetch_ohlcvc(self, symbol, timeframe='1m', since=None, limit=None, params={}): if not self.has['fetchTrades']: raise NotSupported('fetch_ohlcv() not implemented yet') await self.load_markets() trades = await self.fetch_trades(symbol, since, limit, params) return self.build_ohlcvc(trades, timeframe, since, limit)
def fetch_closed_orders(self, symbol=None, since=None, limit=None, params={}): raise NotSupported(self.id + ' fetch_closed_orders() is not implemented yet')
def get_currency_name(self, code): # todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method if code in self.options['currencyNames']: return self.options['currencyNames'][code] raise NotSupported(self.id + ' ' + code + ' not supported for withdrawal')
def fetch_ohlcv(self, symbol, timeframe='1m', since=None, limit=None, params={}): raise NotSupported(self.id + ' API does not allow to fetch OHLCV series for now')
async def fetch_ticker(self, symbol, params={}): raise NotSupported('fetch_ticker() not supported yet')
def get_currency_name(self, code): if code in self.options['currencyNames']: return self.options['currencyNames'][code] raise NotSupported(self.id + ' ' + code + ' not supported for withdrawal')
async def fetch_withdrawals(self, code=None, since=None, limit=None, params={}): raise NotSupported('fetch_withdrawals() is not supported yet')
async def cancel_order(self, id, symbol=None, params={}): raise NotSupported(self.id + ' cancelOrder() is not fully implemented yet')
async def perform_order_book_request(self, market, limit=None, params={}): raise NotSupported(self.id + ' performOrderBookRequest not supported yet')
def fetch_tickers(self, symbols=None, params={}): raise NotSupported( self.id + ' API does not allow to fetch all tickers at once with a single call to fetch_tickers () for now' )
async def fetch_trading_fee(self, symbol, params={}): if not self.has['fetchTradingFees']: raise NotSupported('fetch_trading_fee() not supported yet') return await self.fetch_trading_fees(params)
def fetch_open_orders(self, symbol=None, params={}): raise NotSupported(self.id + ' fetch_open_orders() not implemented yet')