示例#1
0
 async def subscribe(self, conn: AsyncConnection):
     self.__reset()
     for chan in self.subscription:
         symbols = self.subscription[chan]
         if chan == FUNDING:
             asyncio.create_task(
                 self._funding(symbols))  # TODO: use HTTPAsyncConn
             continue
         if chan == OPEN_INTEREST:
             asyncio.create_task(
                 self._open_interest(symbols))  # TODO: use HTTPAsyncConn
             continue
         if is_authenticated_channel(normalize_channel(self.id, chan)):
             await conn.write(
                 json.dumps({
                     "channel": chan,
                     "op": "subscribe"
                 }))
             continue
         for pair in symbols:
             await conn.write(
                 json.dumps({
                     "channel": chan,
                     "market": pair,
                     "op": "subscribe"
                 }))
示例#2
0
 async def subscribe(self, conn: AsyncConnection):
     self._reset()
     for chan in self.subscription:
         symbols = self.subscription[chan]
         nchan = normalize_channel(self.id, chan)
         if nchan in {L2_BOOK, CANDLES}:
             for symbol in symbols:
                 await conn.write(
                     json.dumps({
                         "time":
                         int(time.time()),
                         "channel":
                         chan,
                         "event":
                         'subscribe',
                         "payload": [symbol, '100ms'] if nchan == L2_BOOK
                         else [self.candle_interval, symbol],
                     }))
         else:
             await conn.write(
                 json.dumps({
                     "time": int(time.time()),
                     "channel": chan,
                     "event": 'subscribe',
                     "payload": symbols,
                 }))
示例#3
0
    async def subscribe(self, conn: AsyncConnection):
        self.__reset()

        for chan, symbols in self.subscription.items():
            for symbol in symbols:
                msg = {"type": "subscribe", "channel": chan, "id": symbol}
                if normalize_channel(self.id, chan) == L2_BOOK:
                    msg['includeOffsets'] = True
                await conn.write(json.dumps(msg))
示例#4
0
    async def subscribe(self, conn: AsyncConnection, options: Tuple[str, List[str]] = None):
        chan = options[0]
        symbols = options[1]
        sub = {"name": chan}
        if normalize_channel(self.id, chan) == L2_BOOK:
            max_depth = self.max_depth if self.max_depth else 1000
            if max_depth not in self.valid_depths:
                for d in self.valid_depths:
                    if d > max_depth:
                        max_depth = d

            sub['depth'] = max_depth
        if normalize_channel(self.id, chan) == CANDLES:
            sub['interval'] = self.candle_interval

        await conn.write(json.dumps({
            "event": "subscribe",
            "pair": symbols,
            "subscription": sub
        }))
示例#5
0
    def _address(self) -> Union[str, Dict]:
        """
        Binance has a 200 pair/stream limit per connection, so we need to break the address
        down into multiple connections if necessary. Because the key is currently not used
        for the address dict, we can just set it to the last used stream, since this will be
        unique.

        The generic connect method supplied by Feed will take care of creating the
        correct connection objects from the addresses.
        """
        if self.requires_authentication:
            listen_key = self.auth.generate_token()
            address = self.ws_endpoint + '/ws/' + listen_key
        else:
            address = self.ws_endpoint + '/stream?streams='
        subs = []

        is_any_private = any(is_authenticated_channel(chan) for chan in self.subscription)
        is_any_public = any(not is_authenticated_channel(chan) for chan in self.subscription)
        if is_any_private and is_any_public:
            raise ValueError("Private and public channels should be subscribed to in separate feeds")

        for chan in self.subscription:
            normalized_chan = normalize_channel(self.id, chan)
            if normalized_chan == OPEN_INTEREST:
                continue
            if is_authenticated_channel(normalized_chan):
                continue

            stream = chan
            if normalized_chan == CANDLES:
                stream = f"{chan}{self.candle_interval}"

            for pair in self.subscription[chan]:
                # for everything but premium index the symbols need to be lowercase.
                if pair.startswith("p"):
                    if normalized_chan != CANDLES:
                        raise ValueError("Premium Index Symbols only allowed on Candle data feed")
                else:
                    pair = pair.lower()
                sub = f"{pair}@{stream}"
                if normalized_chan == FUTURES_INDEX:
                    pair = pair.split('_')[0]
                    sub = f"{pair}@{stream}@1s"
                subs.append(sub)

        if len(subs) < 200:
            return address + '/'.join(subs)
        else:
            def split_list(_list: list, n: int):
                for i in range(0, len(_list), n):
                    yield _list[i:i + n]
            return {chunk[0]: address + '/'.join(chunk) for chunk in split_list(subs, 200)}
示例#6
0
    def _address(self) -> Union[str, Dict]:
        """
        Binance has a 200 pair/stream limit per connection, so we need to break the address
        down into multiple connections if necessary. Because the key is currently not used
        for the address dict, we can just set it to the last used stream, since this will be
        unique.

        The generic connect method supplied by Feed will take care of creating the
        correct connection objects from the addresses.
        """
        ret = {}
        counter = 0
        address = self.ws_endpoint + '/stream?streams='

        for chan in self.channels if not self.subscription else self.subscription:
            if normalize_channel(self.id, chan) == OPEN_INTEREST:
                continue
            if normalize_channel(self.id, chan) == CANDLES:
                chan = f"{chan}{self.candle_interval}"

            for pair in self.symbols if not self.subscription else self.subscription[
                    chan]:
                pair = pair.lower()
                stream = f"{pair}@{chan}/"
                address += stream
                counter += 1
                if counter == 200:
                    ret[stream] = address[:-1]
                    counter = 0
                    address = self.ws_endpoint + '/stream?streams='

        if len(ret) == 0:
            if address == f"{self.ws_endpoint}/stream?streams=":
                return None
            return address[:-1]
        if counter > 0:
            ret[stream] = address[:-1]
        return ret
示例#7
0
 async def subscribe(self, conn: AsyncConnection):
     self.__reset()
     client_id = 0
     for chan in self.subscription:
         for pair in self.subscription[chan]:
             client_id += 1
             normalized_chan = normalize_channel(self.id, chan)
             await conn.write(
                 json.dumps({
                     "sub":
                     f"market.{pair}.{chan}" if normalized_chan != CANDLES
                     else f"market.{pair}.{chan}.{self.candle_interval}",
                     "id":
                     client_id
                 }))
示例#8
0
 async def subscribe(self, conn: AsyncConnection):
     self.__reset()
     client_id = 0
     for chan in self.subscription:
         if chan == FUNDING:
             continue
         for pair in self.subscription[chan]:
             client_id += 1
             pair = self.exchange_symbol_to_std_symbol(pair)
             normalized_chan = normalize_channel(self.id, chan)
             await conn.write(json.dumps(
                 {
                     "sub": f"market.{pair}.{chan}" if normalized_chan != CANDLES else f"market.{pair}.{chan}.{self.candle_interval}",
                     "id": str(client_id)
                 }
             ))
示例#9
0
    def _address(self) -> Union[str, Dict]:
        """
        Binance has a 200 pair/stream limit per connection, so we need to break the address
        down into multiple connections if necessary. Because the key is currently not used
        for the address dict, we can just set it to the last used stream, since this will be
        unique.

        The generic connect method supplied by Feed will take care of creating the
        correct connection objects from the addresses.
        """
        ret = {}
        counter = 0
        address = self.ws_endpoint + '/stream?streams='

        for chan in self.channels if not self.subscription else self.subscription:
            normalized_chan = normalize_channel(self.id, chan)

            if normalize_channel == OPEN_INTEREST:
                continue

            stream = chan
            if normalized_chan == CANDLES:
                stream = f"{chan}{self.candle_interval}"

            for pair in self.symbols if not self.subscription else self.subscription[chan]:
                # for everything but premium index the symbols need to be lowercase.
                if pair.startswith("p"):
                    if normalized_chan != CANDLES:
                        raise ValueError("Premium Index Symbols only allowed on Candle data feed")
                else:
                    pair = pair.lower()

                stream = f"{pair}@{stream}/"
                address += stream
                counter += 1
                if counter == 200:
                    ret[stream] = address[:-1]
                    counter = 0
                    address = self.ws_endpoint + '/stream?streams='

        if len(ret) == 0:
            if address == f"{self.ws_endpoint}/stream?streams=":
                return None
            return address[:-1]
        if counter > 0:
            ret[stream] = address[:-1]
        return ret
示例#10
0
    def _address(self) -> Union[str, Dict]:
        """
        Binance has a 200 pair/stream limit per connection, so we need to break the address
        down into multiple connections if necessary. Because the key is currently not used
        for the address dict, we can just set it to the last used stream, since this will be
        unique.

        The generic connect method supplied by Feed will take care of creating the
        correct connection objects from the addresses.
        """
        address = self.ws_endpoint + '/stream?streams='
        subs = []

        for chan in self.channels if not self.subscription else self.subscription:
            normalized_chan = normalize_channel(self.id, chan)
            if normalize_channel == OPEN_INTEREST:
                continue

            stream = chan
            if normalized_chan == CANDLES:
                stream = f"{chan}{self.candle_interval}"

            for pair in self.symbols if not self.subscription else self.subscription[
                    chan]:
                # for everything but premium index the symbols need to be lowercase.
                if pair.startswith("p"):
                    if normalized_chan != CANDLES:
                        raise ValueError(
                            "Premium Index Symbols only allowed on Candle data feed"
                        )
                else:
                    pair = pair.lower()
                subs.append(f"{pair}@{stream}")

        if len(subs) < 200:
            return address + '/'.join(subs)
        else:

            def split_list(_list: list, n: int):
                for i in range(0, len(_list), n):
                    yield _list[i:i + n]

            return {
                chunk[0]: address + '/'.join(chunk)
                for chunk in split_list(subs, 200)
            }
示例#11
0
    async def message_handler(self, msg: str, conn: AsyncConnection,
                              timestamp: float):
        msg = json.loads(msg, parse_float=Decimal)

        if msg['type'] == 'channel_data' or msg['type'] == 'subscribed':
            chan = normalize_channel(self.id, msg['channel'])
            if chan == L2_BOOK:
                await self._book(msg, timestamp)
            elif chan == TRADES:
                await self._trade(msg, timestamp)
            else:
                LOG.warning("%s: unexpected channel type received: %s",
                            self.id, msg)
        elif msg['type'] == 'connected':
            return
        else:
            LOG.warning("%s: Invalid message type %s", self.id, msg)
示例#12
0
 async def subscribe(self, conn: AsyncConnection):
     self.__reset()
     # H: Hub, M: Message, A: Args, I: Internal ID
     # For more signalR info see:
     # https://blog.3d-logic.com/2015/03/29/signalr-on-the-wire-an-informal-description-of-the-signalr-protocol/
     # http://blogs.microsoft.co.il/applisec/2014/03/12/signalr-message-format/
     for chan in self.subscription:
         channel = normalize_channel(self.id, chan)
         i = 1
         for symbol in self.subscription[chan]:
             if channel == L2_BOOK:
                 msg = {
                     'A': ([chan.format(symbol, self.depth)], ),
                     'H': 'c3',
                     'I': i,
                     'M': 'Subscribe'
                 }
             elif channel in (TRADES, TICKER):
                 msg = {
                     'A': ([chan.format(symbol)], ),
                     'H': 'c3',
                     'I': i,
                     'M': 'Subscribe'
                 }
             elif channel == CANDLES:
                 interval = None
                 if self.candle_interval == '1m':
                     interval = 'MINUTE_1'
                 elif self.candle_interval == '5m':
                     interval = 'MINUTE_5'
                 elif self.candle_interval == '1h':
                     interval = 'HOUR_1'
                 elif self.candle_interval == '1d':
                     interval = 'DAY_1'
                 msg = {
                     'A': ([chan.format(symbol, interval)], ),
                     'H': 'c3',
                     'I': i,
                     'M': 'Subscribe'
                 }
             else:
                 LOG.error("%s: invalid subscription for channel %s",
                           channel)
             await conn.write(json.dumps(msg))
             i += 1
示例#13
0
    async def message_handler(self, msg: str, conn, timestamp: float):
        msg = json.loads(msg, parse_float=Decimal)
        if msg['type'] in {'welcome', 'ack'}:
            return

        topic, symbol = msg['topic'].split(":", 1)
        topic = normalize_channel(self.id, topic)

        if topic == TICKER:
            await self._ticker(msg, symbol, timestamp)
        elif topic == TRADES:
            await self._trades(msg, symbol, timestamp)
        elif topic == CANDLES:
            await self._candles(msg, symbol, timestamp)
        elif topic == L2_BOOK:
            await self._l2_book(msg, symbol, timestamp)
        else:
            LOG.warning("%s: Unhandled message type %s", self.id, msg)
示例#14
0
 async def subscribe(self, conn: AsyncConnection):
     self.__reset()
     for chan in self.subscription:
         symbols = self.subscription[chan]
         nchan = normalize_channel(self.id, chan)
         if nchan == CANDLES:
             for symbol in symbols:
                 await conn.write(json.dumps({
                     'id': 1,
                     'type': 'subscribe',
                     'topic': f"{chan}:{symbol}_{self.candle_interval}",
                     'privateChannel': False,
                     'response': True
                 }))
         else:
             await conn.write(json.dumps({
                 'id': 1,
                 'type': 'subscribe',
                 'topic': f"{chan}:{','.join(symbols)}",
                 'privateChannel': False,
                 'response': True
             }))