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" }))
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, }))
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))
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 }))
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)}
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
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 }))
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) } ))
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
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) }
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)
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
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)
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 }))