def tickers(self, assets): """ Retrieve current tick data for the given assets Parameters ---------- assets: list[TradingPair] Returns ------- list[dict[str, float] """ tickers = {} for asset in assets: symbol = self.get_symbol(asset) # Test the CCXT throttling further to see if we need this self.ask_request() # TODO: use fetch_tickers() for efficiency # I tried using fetch_tickers() but noticed some # inconsistencies, see issue: # https://github.com/ccxt/ccxt/issues/870 try: ticker = self.api.fetch_ticker(symbol=symbol) except (ExchangeError, NetworkError) as e: log.warn( 'unable to fetch ticker {} / {}: {}'.format( self.name, asset.symbol, e ) ) continue ticker['last_traded'] = from_ms_timestamp(ticker['timestamp']) if 'last_price' not in ticker: # TODO: any more exceptions? ticker['last_price'] = ticker['last'] if 'baseVolume' in ticker and ticker['baseVolume'] is not None: # Using the volume represented in the base currency ticker['volume'] = ticker['baseVolume'] elif 'info' in ticker and 'bidQty' in ticker['info'] \ and 'askQty' in ticker['info']: ticker['volume'] = float(ticker['info']['bidQty']) + \ float(ticker['info']['askQty']) else: ticker['volume'] = 0 tickers[asset] = ticker return tickers
def get_orderbook(self, asset, order_type='all', limit=None): ccxt_symbol = self.get_symbol(asset) order_book = self.api.fetch_order_book(ccxt_symbol, limit=limit) order_types = ['bids', 'asks'] if order_type == 'all' else [order_type] result = dict(last_traded=from_ms_timestamp(order_book['timestamp'])) for index, order_type in enumerate(order_types): if limit is not None and index > limit - 1: break result[order_type] = [] for entry in order_book[order_type]: result[order_type].append( dict(rate=float(entry[0]), quantity=float(entry[1]))) return result
def get_orderbook(self, asset, order_type='all', limit=None): ccxt_symbol = self.get_symbol(asset) params = dict() if limit is not None: params['depth'] = limit order_book = self.api.fetch_order_book(ccxt_symbol, params) order_types = ['bids', 'asks'] if order_type == 'all' else [order_type] result = dict(last_traded=from_ms_timestamp(order_book['timestamp'])) for index, order_type in enumerate(order_types): if limit is not None and index > limit - 1: break result[order_type] = [] for entry in order_book[order_type]: result[order_type].append(dict( rate=float(entry[0]), quantity=float(entry[1]) )) return result
def _create_order(self, order_status): """ Create a Catalyst order object from a CCXT order dictionary Parameters ---------- order_status: dict[str, Object] The order dict from the CCXT api. Returns ------- Order The Catalyst order object """ order_id = order_status['id'] symbol = self.get_symbol(order_status['symbol'], source='ccxt') asset = self.get_asset(symbol) s = order_status['status'] amount = order_status['amount'] filled = order_status['filled'] if s == 'canceled' or (s == 'closed' and filled == 0): status = ORDER_STATUS.CANCELLED elif s == 'closed' and filled > 0: if filled < amount: log.warn( 'order {id} is executed but only partially filled:' ' {filled} {symbol} out of {amount}'.format( id=order_status['status'], filled=order_status['filled'], symbol=asset.symbol, amount=order_status['amount'], ) ) else: log.info( 'order {id} executed in full: {filled} {symbol}'.format( id=order_id, filled=filled, symbol=asset.symbol, ) ) status = ORDER_STATUS.FILLED elif s == 'open': status = ORDER_STATUS.OPEN elif filled > 0: log.info( 'order {id} partially filled: {filled} {symbol} out of ' '{amount}, waiting for complete execution'.format( id=order_id, filled=filled, symbol=asset.symbol, amount=amount, ) ) status = ORDER_STATUS.OPEN else: log.warn( 'invalid state {} for order {}'.format( s, order_id ) ) status = ORDER_STATUS.OPEN if order_status['side'] == 'sell': amount = -amount filled = -filled price = order_status['price'] order_type = order_status['type'] limit_price = price if order_type == 'limit' else None executed_price = order_status['cost'] / order_status['amount'] commission = order_status['fee'] date = from_ms_timestamp(order_status['timestamp']) order = Order( dt=date, asset=asset, amount=amount, stop=None, limit=limit_price, filled=filled, id=order_id, commission=commission ) order.status = status return order, executed_price
def tickers(self, assets, on_ticker_error='raise'): """ Retrieve current tick data for the given assets Parameters ---------- assets: list[TradingPair] Returns ------- list[dict[str, float] """ if len(assets) == 1: try: symbol = self.get_symbol(assets[0]) log.debug('fetching single ticker: {}'.format(symbol)) results = dict() results[symbol] = self.api.fetch_ticker(symbol=symbol) except ( ExchangeError, NetworkError, ) as e: log.warn('unable to fetch ticker {} / {}: {}'.format( self.name, symbol, e)) raise ExchangeRequestError(error=e) elif len(assets) > 1: symbols = self.get_symbols(assets) try: log.debug('fetching multiple tickers: {}'.format(symbols)) results = self.api.fetch_tickers(symbols=symbols) except (ExchangeError, NetworkError) as e: log.warn('unable to fetch tickers {} / {}: {}'.format( self.name, symbols, e)) raise ExchangeRequestError(error=e) else: raise ValueError('Cannot request tickers with not assets.') tickers = dict() for asset in assets: symbol = self.get_symbol(asset) if symbol not in results: msg = 'ticker not found {} / {}'.format(self.name, symbol) log.warn(msg) if on_ticker_error == 'warn': continue else: raise ExchangeRequestError(error=msg) ticker = results[symbol] ticker['last_traded'] = from_ms_timestamp(ticker['timestamp']) if 'last_price' not in ticker: # TODO: any more exceptions? ticker['last_price'] = ticker['last'] if 'baseVolume' in ticker and ticker['baseVolume'] is not None: # Using the volume represented in the base currency ticker['volume'] = ticker['baseVolume'] elif 'info' in ticker and 'bidQty' in ticker['info'] \ and 'askQty' in ticker['info']: ticker['volume'] = float(ticker['info']['bidQty']) + \ float(ticker['info']['askQty']) else: ticker['volume'] = 0 tickers[asset] = ticker return tickers
def _create_order(self, order_status): """ Create a Catalyst order object from a CCXT order dictionary Parameters ---------- order_status: dict[str, Object] The order dict from the CCXT api. Returns ------- Order The Catalyst order object """ order_id = order_status['id'] symbol = self.get_symbol(order_status['symbol'], source='ccxt') asset = self.get_asset(symbol) s = order_status['status'] amount = order_status['amount'] filled = order_status['filled'] if s == 'canceled' or (s == 'closed' and filled == 0): status = ORDER_STATUS.CANCELLED elif s == 'closed' and filled > 0: if filled < amount: log.warn( 'order {id} is executed but only partially filled:' ' {filled} {symbol} out of {amount}'.format( id=order_status['status'], filled=order_status['filled'], symbol=asset.symbol, amount=order_status['amount'], ) ) else: log.info( 'order {id} executed in full: {filled} {symbol}'.format( id=order_id, filled=filled, symbol=asset.symbol, ) ) status = ORDER_STATUS.FILLED elif s == 'open': status = ORDER_STATUS.OPEN elif filled > 0: log.info( 'order {id} partially filled: {filled} {symbol} out of ' '{amount}, waiting for complete execution'.format( id=order_id, filled=filled, symbol=asset.symbol, amount=amount, ) ) status = ORDER_STATUS.OPEN else: log.warn( 'invalid state {} for order {}'.format( s, order_id ) ) status = ORDER_STATUS.OPEN if order_status['side'] == 'sell': amount = -amount filled = -filled price = order_status['price'] order_type = order_status['type'] limit_price = price if order_type == 'limit' else None executed_price = order_status['cost'] / order_status['amount'] commission = order_status['fee'] date = from_ms_timestamp(order_status['timestamp']) order = Order( dt=date, asset=asset, amount=amount, stop=None, limit=limit_price, filled=filled, id=order_id, commission=commission ) order.status = status return order, executed_price
def tickers(self, assets, on_ticker_error='raise'): """ Retrieve current tick data for the given assets Parameters ---------- assets: list[TradingPair] Returns ------- list[dict[str, float] """ if len(assets) == 1: try: symbol = self.get_symbol(assets[0]) log.debug('fetching single ticker: {}'.format(symbol)) results = dict() results[symbol] = self.api.fetch_ticker(symbol=symbol) except (ExchangeError, NetworkError,) as e: log.warn( 'unable to fetch ticker {} / {}: {}'.format( self.name, symbol, e ) ) raise ExchangeRequestError(error=e) elif len(assets) > 1: symbols = self.get_symbols(assets) try: log.debug('fetching multiple tickers: {}'.format(symbols)) results = self.api.fetch_tickers(symbols=symbols) except (ExchangeError, NetworkError) as e: log.warn( 'unable to fetch tickers {} / {}: {}'.format( self.name, symbols, e ) ) raise ExchangeRequestError(error=e) else: raise ValueError('Cannot request tickers with not assets.') tickers = dict() for asset in assets: symbol = self.get_symbol(asset) if symbol not in results: msg = 'ticker not found {} / {}'.format( self.name, symbol ) log.warn(msg) if on_ticker_error == 'warn': continue else: raise ExchangeRequestError(error=msg) ticker = results[symbol] ticker['last_traded'] = from_ms_timestamp(ticker['timestamp']) if 'last_price' not in ticker: # TODO: any more exceptions? ticker['last_price'] = ticker['last'] if 'baseVolume' in ticker and ticker['baseVolume'] is not None: # Using the volume represented in the base currency ticker['volume'] = ticker['baseVolume'] elif 'info' in ticker and 'bidQty' in ticker['info'] \ and 'askQty' in ticker['info']: ticker['volume'] = float(ticker['info']['bidQty']) + \ float(ticker['info']['askQty']) else: ticker['volume'] = 0 tickers[asset] = ticker return tickers