Пример #1
0
    def __init__(self,
                 address,
                 pairs=None,
                 channels=None,
                 config=None,
                 callbacks=None,
                 book_interval=1000):
        self.config = {}
        self.address = address
        self.book_update_interval = book_interval
        self.updates = 0
        self.do_deltas = False
        self.pairs = []
        self.channels = []

        load_exchange_pair_mapping(self.id)

        if channels is not None and FUNDING in channels and self.id == BITFINEX:
            if len(channels) > 1:
                raise ValueError(
                    "Funding channel must be in a separate feedhanlder on Bitfinex or you must use config"
                )

        if config is not None and (pairs is not None or channels is not None):
            raise ValueError("Use config, or channels and pairs, not both")

        if config is not None:
            for channel in config:
                chan = feed_to_exchange(self.id, channel)
                self.config[chan] = [
                    pair_std_to_exchange(pair, self.id)
                    for pair in config[channel]
                ]

        if pairs:
            self.pairs = [
                pair_std_to_exchange(pair, self.id) for pair in pairs
            ]
        if channels:
            self.channels = [
                feed_to_exchange(self.id, chan) for chan in channels
            ]

        self.l3_book = {}
        self.l2_book = {}
        self.callbacks = {
            TRADES: Callback(None),
            TICKER: Callback(None),
            L2_BOOK: Callback(None),
            L3_BOOK: Callback(None),
            VOLUME: Callback(None),
            FUNDING: Callback(None)
        }

        if callbacks:
            for cb_type, cb_func in callbacks.items():
                self.callbacks[cb_type] = cb_func
                if cb_type == BOOK_DELTA:
                    self.do_deltas = True
Пример #2
0
    def __init__(self,
                 address,
                 pairs=None,
                 channels=None,
                 config=None,
                 callbacks=None,
                 book_interval=1000):
        self.hash = str(uuid.uuid4())
        self.uuid = self.id + self.hash
        self.config = {}
        self.address = address
        self.book_update_interval = book_interval
        self.updates = 0
        self.do_deltas = False
        self.pairs = []
        self.channels = []
        load_exchange_pair_mapping(self.id)

        if config is not None and (pairs is not None or channels is not None):
            raise ValueError("Use config, or channels and pairs, not both")

        if config is not None:
            for channel in config:
                chan = feed_to_exchange(self.id, channel)
                self.config[chan] = [
                    pair_std_to_exchange(pair, self.id)
                    for pair in config[channel]
                ]

        if pairs:
            self.pairs = [
                pair_std_to_exchange(pair, self.id) for pair in pairs
            ]
        if channels:
            self.channels = [
                feed_to_exchange(self.id, chan) for chan in channels
            ]

        self.l3_book = {}
        self.l2_book = {}
        self.callbacks = {
            TRADES: Callback(None),
            TICKER: Callback(None),
            L2_BOOK: Callback(None),
            L3_BOOK: Callback(None),
            VOLUME: Callback(None),
            FUNDING: Callback(None),
            INSTRUMENT: Callback(None)
        }

        if callbacks:
            for cb_type, cb_func in callbacks.items():
                self.callbacks[cb_type] = cb_func
                if cb_type == BOOK_DELTA:
                    self.do_deltas = True

        for key, callback in self.callbacks.items():
            if not isinstance(callback, list):
                self.callbacks[key] = [callback]
Пример #3
0
    def __init__(self, address, pairs=None, channels=None, config=None, callbacks=None, max_depth=None, book_interval=1000, cross_check=False, origin=None):
        self.hash = str(uuid.uuid4())
        self.uuid = self.id + self.hash
        self.config = defaultdict(set)
        self.address = address
        self.book_update_interval = book_interval
        self.cross_check = cross_check
        self.updates = defaultdict(int)
        self.do_deltas = False
        self.pairs = []
        self.channels = []
        self.max_depth = max_depth
        self.previous_book = defaultdict(dict)
        self.origin = origin
        load_exchange_pair_mapping(self.id)

        if config is not None and (pairs is not None or channels is not None):
            raise ValueError("Use config, or channels and pairs, not both")

        if config is not None:
            for channel in config:
                chan = feed_to_exchange(self.id, channel)
                self.config[chan].update([pair_std_to_exchange(pair, self.id) for pair in config[channel]])

        if pairs:
            self.pairs = [pair_std_to_exchange(pair, self.id) for pair in pairs]
        if channels:
            self.channels = list(set([feed_to_exchange(self.id, chan) for chan in channels]))

        self.l3_book = {}
        self.l2_book = {}
        self.callbacks = {
        TICKER_OKS: Callback(None),
        TICKER_FUTURES: Callback(None),TRADES: Callback(None),
                          TICKER: Callback(None),
                          L2_BOOK: Callback(None),
                          L3_BOOK: Callback(None),
                          VOLUME: Callback(None),
                          FUNDING: Callback(None),
                          OPEN_INTEREST: Callback(None),
                          LIQUIDATIONS: Callback(None)}

        if callbacks:
            for cb_type, cb_func in callbacks.items():
                self.callbacks[cb_type] = cb_func
                if cb_type == BOOK_DELTA:
                    self.do_deltas = True

        for key, callback in self.callbacks.items():
            if not isinstance(callback, list):
                self.callbacks[key] = [callback]
Пример #4
0
    def _get_orders(self, body):
        """
        https://docs.gdax.com/?python#list-orders
        """
        endpoint = "/orders"
        if 'status' in body:
            for status in body['status']:
                if 'status' not in endpoint:
                    endpoint = '{}?status={}'.format(endpoint, status)
                else:
                    endpoint = '{}&status{}'.format(endpoint, status)

        if 'product_id' in body:
            product_id = pair_std_to_exchange(body['product_id'], self.ID)
            if 'status' in endpoint:
                endpoint = '{}&product_id={}'.format(endpoint, product_id)
            else:
                endpoint = '{}?product_id={}'.format(endpoint, product_id)

        endpoint = self._pagination(endpoint, body)

        header = self._generate_signature(endpoint, "GET")
        data = self._make_request("GET", endpoint, header)
        data = list(map(self._trade_normalization, data))

        return data
Пример #5
0
    def trades(self, symbol: str, start=None, end=None, retry=None, retry_wait=10):
        sym = pair_std_to_exchange(symbol, self.ID)
        params = {'limit_trades': 500}
        if start:
            params['since'] = int(pd.Timestamp(start).timestamp() * 1000)
        if end:
            end_ts = int(pd.Timestamp(end).timestamp() * 1000)

        def _trade_normalize(trade):
            return {
                'feed': self.ID,
                'order_id': trade['tid'],
                'pair': sym,
                'side': trade['type'],
                'amount': Decimal(trade['amount']),
                'price': Decimal(trade['price']),
                'timestamp': trade['timestampms'] / 1000.0
            }

        while True:
            data = reversed(self._get(f"/v1/trades/{sym}?", retry, retry_wait, params=params))
            if end:
                data = [_trade_normalize(d) for d in data if d['timestampms'] <= end_ts]
            else:
                data = [_trade_normalize(d) for d in data]
            yield data

            if start:
                params['since'] = int(data[-1]['timestamp'] * 1000) + 1
            if len(data) < 500:
                break
            if not start and not end:
                break
            # GEMINI rate limits to 120 requests a minute
            sleep(0.5)
Пример #6
0
    def _book(self, symbol: str, retry=0, retry_wait=0):
        ret = {}
        symbol = pair_std_to_exchange(symbol, self.ID)
        ret[symbol] = {BID: sd(), ASK: sd()}

        @request_retry(self.ID, retry, retry_wait)
        def helper():
            return requests.get(
                f"{self.api}get_order_book?depth=10000&instrument_name={symbol}"
            )

        while True:
            r = helper()

            if r.status_code == 429:
                sleep(int(r.headers['Retry-After']))
                continue
            elif r.status_code == 500:
                LOG.warning("%s: 500 for URL %s - %s", self.ID, r.url, r.text)
                sleep(retry_wait)
                if retry == 0:
                    break
                continue
            elif r.status_code != 200:
                self._handle_error(r, LOG)

            data = r.json()
            break

        for side, key in ((BID, 'bids'), (ASK, 'asks')):
            for entry_bid in data["result"][key]:
                price, amount = entry_bid
                ret[symbol][side][price] = amount

        return ret
Пример #7
0
    def place_order(self,
                    symbol: str,
                    side: str,
                    order_type: str,
                    amount: Decimal,
                    price=None,
                    options=None):
        ot = normalize_trading_options(self.ID, order_type)

        parameters = {
            'pair': pair_std_to_exchange(symbol, self.ID + 'REST'),
            'type': 'buy' if side == BUY else 'sell',
            'volume': str(amount),
            'ordertype': ot
        }

        if price is not None:
            parameters['price'] = str(price)

        if options:
            parameters['oflags'] = ','.join(
                [normalize_trading_options(self.ID, o) for o in options])

        data = self._post_private('/private/AddOrder', parameters)
        if len(data['error']) != 0:
            return data
        else:
            if len(data['result']['txid']) == 1:
                return self.order_status(data['result']['txid'][0])
            else:
                return [self.order_status(tx) for tx in data['result']['txid']]
Пример #8
0
    def _get_fills(self,
                   symbol=None,
                   retry=None,
                   retry_wait=0,
                   start_date=None,
                   end_date=None):
        endpoint = '/fills'
        if symbol is not None:
            symbol = pair_std_to_exchange(symbol, self.ID)
            endpoint = '{}?product_id={}'.format(endpoint, symbol)

        header = self._generate_signature(endpoint, "GET")
        data = self._make_request("GET", endpoint, header, retry=retry)

        if data == []:
            LOG.warning("%s: No data", self.ID)
        elif start_date is not None and end_date is not None:
            # filter out data not in specified range
            data_in_range = []
            start_time = pd.Timestamp(start_date).to_pydatetime()
            end_time = pd.Timestamp(end_date).to_pydatetime()
            for entry in data:
                entry_time = dt.strptime(entry['created_at'],
                                         "%Y-%m-%dT%H:%M:%S.%fZ")

                if entry_time >= start_time and entry_time <= end_time:
                    data_in_range.append(entry)
            data = data_in_range

        data = list(map(self._trade_normalization, data))
        return data
Пример #9
0
    def place_order(self, symbol: str, side: str, order_type: str, amount: Decimal, price=None, options=None):
        if not price:
            raise ValueError('Poloniex only supports limit orders, must specify price')
        # Poloniex only supports limit orders, so check the order type
        _ = normalize_trading_options(self.ID, order_type)
        parameters = {}
        if options:
            parameters = {
                normalize_trading_options(self.ID, o): 1 for o in options
            }
        parameters['currencyPair'] = pair_std_to_exchange(symbol, self.ID)
        parameters['amount'] = str(amount)
        parameters['rate'] = str(price)

        endpoint = None
        if side == BUY:
            endpoint = 'buy'
        elif side == SELL:
            endpoint = 'sell'

        data = self._post(endpoint, parameters)
        order = self.order_status(data['orderNumber'])

        if 'error' not in order:
            if len(data['resultingTrades']) == 0:
                return order
            else:
                return Poloniex._trade_status(data['resultingTrades'], symbol, data['orderNumber'], amount)
        return data
Пример #10
0
    def __init__(self, address, pairs=None, channels=None, callbacks=None, book_interval=1000):
        self.address = address
        self.standardized_pairs = pairs
        self.standardized_channels = channels
        self.book_update_interval = book_interval
        self.updates = 0
        self.do_deltas = False

        if channels is not None and FUNDING in channels and self.id == BITFINEX:
            if len(channels) > 1:
                raise ValueError("Funding channel must be in a separate feedhanlder on Bitfinex")

        if pairs:
            self.pairs = [pair_std_to_exchange(pair, self.id) for pair in pairs]
        if channels:
            self.channels = [feed_to_exchange(self.id, chan) for chan in channels]

        self.l3_book = {}
        self.l2_book = {}
        self.callbacks = {TRADES: Callback(None),
                          TICKER: Callback(None),
                          L2_BOOK: Callback(None),
                          L3_BOOK: Callback(None),
                          VOLUME: Callback(None),
                          FUNDING: Callback(None)}


        if callbacks:
            for cb in callbacks:
                self.callbacks[cb] = callbacks[cb]
                if isinstance(callbacks[cb], BookUpdateCallback):
                    self.do_deltas = True
Пример #11
0
    def place_order(self,
                    symbol: str,
                    side: str,
                    order_type: str,
                    amount: Decimal,
                    price=None,
                    options=None):
        if not price:
            raise ValueError(
                'Poloniex only supports limit orders, must specify price')
        # Poloniex only supports limit orders, so check the order type
        _ = normalize_trading_options(self.ID, order_type)
        parameters = {
            normalize_trading_options(self.ID, o): 1
            for o in options
        }
        parameters['currencyPair'] = pair_std_to_exchange(symbol, self.ID)
        parameters['amount'] = str(amount)
        parameters['rate'] = str(price)

        endpoint = None
        if side == BUY:
            endpoint = 'buy'
        elif side == SELL:
            endpoint = 'sell'
        return self._post(endpoint, parameters)
Пример #12
0
    def place_order(self,
                    symbol: str,
                    side: str,
                    order_type: str,
                    amount: Decimal,
                    price=None,
                    client_order_id=None,
                    options=None):
        if not price:
            raise ValueError(
                'Gemini only supports limit orders, must specify price')
        ot = normalize_trading_options(self.ID, order_type)
        sym = pair_std_to_exchange(symbol, self.ID)

        parameters = {
            'type':
            ot,
            'symbol':
            sym,
            'side':
            side,
            'amount':
            str(amount),
            'price':
            str(price),
            'options':
            [normalize_trading_options(self.ID, o)
             for o in options] if options else []
        }

        if client_order_id:
            parameters['client_order_id'] = client_order_id

        data = self._post("/v1/order/new", parameters)
        return Gemini._order_status(data)
Пример #13
0
    def __init__(self, address, pairs=None, channels=None, callbacks=None):
        self.address = address
        self.standardized_pairs = pairs
        self.standardized_channels = channels

        if pairs:
            self.pairs = [
                pair_std_to_exchange(pair, self.id) for pair in pairs
            ]
        if channels:
            self.channels = [
                feed_to_exchange(self.id, chan) for chan in channels
            ]

        self.l3_book = {}
        self.l2_book = {}
        self.callbacks = {
            TRADES: Callback(None),
            TICKER: Callback(None),
            L2_BOOK: Callback(None),
            L3_BOOK: Callback(None),
            VOLUME: Callback(None)
        }

        if callbacks:
            for cb in callbacks:
                self.callbacks[cb] = callbacks[cb]
Пример #14
0
    def _historical_trades(self, symbol, start_date, end_date, retry, retry_wait, freq='6H'):
        symbol = pair_std_to_exchange(symbol, self.ID + 'REST')

        @request_retry(self.ID, retry, retry_wait)
        def helper(start_date):
            endpoint = f"{self.api}/public/Trades?pair={symbol}&since={start_date}"
            return requests.get(endpoint)

        start_date = API._timestamp(start_date).timestamp() * 1000000000
        end_date = API._timestamp(end_date).timestamp() * 1000000000

        while start_date < end_date:
            r = helper(start_date)

            if r.status_code == 504 or r.status_code == 520:
                # cloudflare gateway timeout or other error
                time.sleep(60)
                continue
            elif r.status_code != 200:
                self._handle_error(r, LOG)
            else:
                time.sleep(RATE_LIMIT_SLEEP)

            data = r.json()
            if 'error' in data and data['error']:
                if data['error'] == ['EAPI:Rate limit exceeded']:
                    time.sleep(5)
                    continue
                else:
                    raise Exception(f"Error processing URL {r.url}: {data['error']}")

            yield data

            start_date = int(data['result']['last'])
Пример #15
0
    def trades(self, symbol, start=None, end=None, retry=None, retry_wait=10):
        symbol = pair_std_to_exchange(symbol, self.ID)

        @request_retry(self.ID, retry, retry_wait)
        def helper(s=None, e=None):
            data = self._get("returnTradeHistory", {'currencyPair': symbol, 'start': s, 'end': e})
            data.reverse()
            return data

        if not start:
            yield map(lambda x: self._trade_normalize(x, symbol), helper())

        else:
            if not end:
                end = pd.Timestamp.utcnow()
            start = API._timestamp(start)
            end = API._timestamp(end) - pd.Timedelta(nanoseconds=1)

            start = int(start.timestamp())
            end = int(end.timestamp())

            s = start
            e = start + 21600
            while True:
                if e > end:
                    e = end

                yield map(lambda x: self._trade_normalize(x, symbol), helper(s=s, e=e))

                s = e
                e += 21600
                if s >= end:
                    break
Пример #16
0
 def trades(self, symbol):
     symbol = pair_std_to_exchange(symbol, self.ID)
     """
     Parameters:
         pair = asset pair to get trade data for
         since = return trade data since given id (optional.  exclusive)
     """
     return self._post_public("/public/Trades", {'pair': symbol})
Пример #17
0
 def ticker(self, symbol: str, retry=None, retry_wait=0):
     sym = pair_std_to_exchange(symbol, self.ID)
     data = self._get(f"ticker/{sym}", retry, retry_wait)
     return {'pair': symbol,
             'feed': self.ID,
             'bid': Decimal(data[0]),
             'ask': Decimal(data[2])
            }
Пример #18
0
    def trades(self, symbol, start=None, end=None, retry=None, retry_wait=10):
        symbol = pair_std_to_exchange(symbol, self.ID).replace("/", "")

        if start and end:
            for data in self._historical_trades(symbol, start, end, retry, retry_wait):
                yield list(map(lambda x: self._trade_normalization(x, symbol), data['result'][next(iter(data['result']))]))
        else:
            yield self._post_public("/public/Trades", {'pair': symbol})
Пример #19
0
 def ticker(self, symbol: str, retry=None, retry_wait=10):
     sym = pair_std_to_exchange(symbol, self.ID)
     data = self._get("returnTicker", retry=retry, retry_wait=retry_wait)
     return {'pair': symbol,
             'feed': self.ID,
             'bid': Decimal(data[sym]['lowestAsk']),
             'ask': Decimal(data[sym]['highestBid'])
         }
Пример #20
0
 def trades(self,
            symbol: str,
            start=None,
            end=None,
            retry=None,
            retry_wait=10):
     symbol = pair_std_to_exchange(symbol, self.ID)
     for data in self._get_trades(symbol, start, end, retry, retry_wait):
         yield data
    def ticker(self, symbol: str, retry=None, retry_wait=0):
        sym = pair_std_to_exchange(symbol, self.ID)
        data = self._get(f"/markets/{sym}", retry=retry, retry_wait=retry_wait)

        return {'pair': symbol,
                'feed': self.ID,
                'bid': data['result']['bid'],
                'ask': data['result']['ask']
                }
Пример #22
0
    def trade_history(self, symbol: str, start=None, end=None):
        payload = {'currencyPair': pair_std_to_exchange(symbol, self.ID)}

        if start:
            payload['start'] = API._timestamp(start).timestamp()
        if end:
            payload['end'] = API._timestamp(end).timestamp()

        payload['limit'] = 10000
        return self._post("returnTradeHistory", payload)
Пример #23
0
def feed_to_exchange(exchange, feed):
    if exchange == POLONIEX:
        if feed not in _feed_to_exchange_map:
            return pair_std_to_exchange(feed, POLONIEX)

    ret = _feed_to_exchange_map[feed][exchange]
    if ret == UNSUPPORTED:
        LOG.error("{} is not supported on {}".format(feed, exchange))
        raise ValueError("{} is not supported on {}".format(feed, exchange))
    return ret
 def __init__(self, pairs=None, channels=None, callbacks=None, **kwargs):
     self.channels = None
     if pairs and len(pairs) == 1:
         self.pair = pairs[0]
         super().__init__('wss://bitmax.io/api/public/', pairs=None, channels=None, callbacks=callbacks, **kwargs)
         self.address += pair_std_to_exchange(self.pair, self.id).replace('/', '-')
         self.pairs = pairs
     else:
         self.pairs = pairs
         self.config = kwargs.get('config', None)
         self.callbacks = callbacks
Пример #25
0
 def l2_book(self, symbol: str, retry=None, retry_wait=0):
     sym = pair_std_to_exchange(symbol, self.ID)
     data = self._get("returnOrderBook", {'currencyPair': sym},
                      retry=retry,
                      retry_wait=retry_wait)
     return {
         BID: sd({Decimal(u[0]): Decimal(u[1])
                  for u in data['bids']}),
         ASK: sd({Decimal(u[0]): Decimal(u[1])
                  for u in data['asks']})
     }
Пример #26
0
    def ticker(self, symbol: str, retry=None, retry_wait=0):
        sym = pair_std_to_exchange(symbol, self.ID + 'REST')
        data = self._post_public(f"/public/Ticker", payload={'pair': sym}, retry=retry, retry_wait=retry_wait)

        data = data['result']
        for _, val in data.items():
            return {'pair': symbol,
                    'feed': self.ID,
                    'bid': Decimal(val['b'][0]),
                    'ask': Decimal(val['a'][0])
                    }
Пример #27
0
 def l2_book(self, symbol: str, retry=None, retry_wait=0):
     sym = pair_std_to_exchange(symbol, self.ID)
     data = self._get(f"/markets/{sym}/orderbook", {'depth': 100},
                      retry=retry,
                      retry_wait=retry_wait)
     return {
         BID: sd({u[0]: u[1]
                  for u in data['result']['bids']}),
         ASK: sd({u[0]: u[1]
                  for u in data['result']['asks']})
     }
Пример #28
0
 def trades(self, symbol: str, start=None, end=None, retry=None, retry_wait=10):
     if start:
         if not end:
             end = pd.Timestamp.utcnow()
         for data in self._historical_trades(symbol, start, end, retry, retry_wait):
             yield list(map(lambda x: self._trade_normalization(x, symbol), data['result'][next(iter(data['result']))]))
     else:
         sym = pair_std_to_exchange(symbol, self.ID + 'REST')
         data = self._post_public("/public/Trades", {'pair': sym}, retry=retry, retry_wait=retry_wait)
         data = data['result']
         data = data[list(data.keys())[0]]
         yield [self._trade_normalization(d, symbol) for d in data]
Пример #29
0
 def l2_book(self, symbol: str, retry=None, retry_wait=0):
     sym = pair_std_to_exchange(symbol, self.ID)
     data = self._get(f"/v1/book/{sym}", retry, retry_wait)
     return {
         BID: sd({
             Decimal(u['price']): Decimal(u['amount'])
             for u in data['bids']
         }),
         ASK: sd({
             Decimal(u['price']): Decimal(u['amount'])
             for u in data['asks']
         })
     }
Пример #30
0
 def trades(self,
            symbol: str,
            start=None,
            end=None,
            retry=None,
            retry_wait=10):
     # funding symbols start with f, eg: fUSD, fBTC, etc
     if symbol[0] != 'f':
         symbol = pair_std_to_exchange(symbol, self.ID)
     if start and end:
         for data in self._get_trades_hist(symbol, start, end, retry,
                                           retry_wait):
             yield data