Пример #1
0
    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
Пример #2
0
    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
Пример #3
0
    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
Пример #4
0
    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
Пример #5
0
    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
Пример #6
0
    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
Пример #7
0
    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