def __init__(self, trading_pairs: List[str], chain: EthereumChain = EthereumChain.MAIN_NET): super().__init__(trading_pairs) self._order_book_create_function = lambda: BambooRelayOrderBook() self._motd_done = False if chain is EthereumChain.ROPSTEN: self._api_endpoint = BAMBOO_RELAY_REST_ENDPOINT self._api_prefix = "ropsten/0x" self._api_ws = BAMBOO_RELAY_REST_WS self._network_id = 3 elif chain is EthereumChain.RINKEBY: self._api_endpoint = BAMBOO_RELAY_REST_ENDPOINT self._api_prefix = "rinkeby/0x" self._api_ws = BAMBOO_RELAY_REST_WS self._network_id = 4 elif chain is EthereumChain.KOVAN: self._api_endpoint = BAMBOO_RELAY_REST_ENDPOINT self._api_prefix = "kovan/0x" self._api_ws = BAMBOO_RELAY_REST_WS self._network_id = 42 elif chain is EthereumChain.ZEROEX_TEST: self._api_endpoint = BAMBOO_RELAY_TEST_ENDPOINT self._api_prefix = "testrpc/0x" self._api_ws = BAMBOO_RELAY_TEST_WS self._network_id = 1337 else: self._api_endpoint = BAMBOO_RELAY_REST_ENDPOINT self._api_prefix = "main/0x" self._api_ws = BAMBOO_RELAY_REST_WS self._network_id = 1
async def listen_for_order_book_snapshots(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue): while True: try: trading_pairs: List[str] = self._trading_pairs client: aiohttp.ClientSession = self.http_client() for trading_pair in trading_pairs: try: snapshot: Dict[str, any] = await self.get_snapshot(client, trading_pair, self._api_endpoint, self._api_prefix) snapshot_timestamp: float = time.time() snapshot_msg: OrderBookMessage = BambooRelayOrderBook.snapshot_message_from_exchange( snapshot, snapshot_timestamp, metadata={"trading_pair": trading_pair} ) output.put_nowait(snapshot_msg) self.logger().debug(f"Saved order book snapshot for {trading_pair}") await asyncio.sleep(5.0) except asyncio.CancelledError: raise except Exception: self.logger().error("Unexpected error.", exc_info=True) await asyncio.sleep(5.0) this_hour: pd.Timestamp = pd.Timestamp.utcnow().replace(minute=0, second=0, microsecond=0) next_hour: pd.Timestamp = this_hour + pd.Timedelta(hours=1) delta: float = next_hour.timestamp() - time.time() await asyncio.sleep(delta) except asyncio.CancelledError: raise except Exception: self.logger().error("Unexpected error.", exc_info=True) await asyncio.sleep(5.0)
async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue): while True: try: trading_pairs: List[str] = await self.get_trading_pairs() async with websockets.connect(WS_URL) as ws: ws: websockets.WebSocketClientProtocol = ws for trading_pair in trading_pairs: request: Dict[str, str] = { "type": "SUBSCRIBE", "topic": "BOOK", "market": trading_pair, "networkId": self._network_id } await ws.send(ujson.dumps(request)) async for raw_msg in self._inner_messages(ws): msg = ujson.loads(raw_msg) # Valid Diff messages from BambooRelay have action key if "action" in msg: diff_msg: BambooRelayOrderBookMessage = BambooRelayOrderBook.diff_message_from_exchange( msg, time.time()) output.put_nowait(diff_msg) except asyncio.CancelledError: raise except Exception: self.logger().error( "Unexpected error with WebSocket connection. Retrying after 30 seconds...", exc_info=True) await asyncio.sleep(30.0)
async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue): while True: try: trading_pairs: List[str] = await self.get_trading_pairs() async with websockets.connect(self._api_ws) as ws: ws: websockets.WebSocketClientProtocol = ws if not self._motd_done: try: raw_msg = await asyncio.wait_for( ws.recv(), timeout=self.MESSAGE_TIMEOUT) msg = ujson.loads(raw_msg) # Print MOTD and announcements if present if "motd" in msg: self._motd_done = True self.logger().info( f"Bamboo Relay API MOTD: {msg['motd']}") if "announcements" in msg and len( msg["announcements"]): for announcement in msg["announcements"]: self.logger().info( f"Announcement: {announcement}") except Exception: pass for trading_pair in trading_pairs: request: Dict[str, str] = { "type": "SUBSCRIBE", "topic": "BOOK", "market": trading_pair, "networkId": self._network_id } await ws.send(ujson.dumps(request)) async for raw_msg in self._inner_messages(ws): # Try here, else any errors cause the websocket to disconnect try: msg = ujson.loads(raw_msg) # Valid Diff messages from BambooRelay have actions array if "actions" in msg: diff_msg: BambooRelayOrderBookMessage = BambooRelayOrderBook.diff_message_from_exchange( msg, time.time()) output.put_nowait(diff_msg) except Exception: pass except asyncio.CancelledError: raise except Exception: self.logger().error( "Unexpected error with WebSocket connection. Retrying after 30 seconds...", exc_info=True) await asyncio.sleep(30.0)
async def get_new_order_book(self, trading_pair: str) -> BambooRelayOrderBook: async with aiohttp.ClientSession() as client: snapshot: Dict[str, any] = await self.get_snapshot(client, trading_pair, self._api_endpoint, self._api_prefix) snapshot_timestamp: float = time.time() snapshot_msg: BambooRelayOrderBookMessage = BambooRelayOrderBook.snapshot_message_from_exchange( snapshot, snapshot_timestamp, metadata={"trading_pair": trading_pair} ) bamboo_relay_active_order_tracker: BambooRelayActiveOrderTracker = BambooRelayActiveOrderTracker() bids, asks = bamboo_relay_active_order_tracker.convert_snapshot_message_to_order_book_row( snapshot_msg) order_book = self.order_book_create_function() order_book.apply_snapshot(bids, asks, snapshot_msg.update_id) return order_book
async def get_tracking_pairs(self) -> Dict[str, OrderBookTrackerEntry]: # Get the currently active markets async with aiohttp.ClientSession() as client: trading_pairs: List[str] = await self.get_trading_pairs() retval: Dict[str, OrderBookTrackerEntry] = {} number_of_pairs: int = len(trading_pairs) for index, trading_pair in enumerate(trading_pairs): try: snapshot: Dict[str, any] = await self.get_snapshot( client, trading_pair, self._api_endpoint, self._api_prefix) snapshot_timestamp: float = time.time() snapshot_msg: BambooRelayOrderBookMessage = BambooRelayOrderBook.snapshot_message_from_exchange( snapshot, snapshot_timestamp, metadata={"trading_pair": trading_pair}) bamboo_relay_order_book: OrderBook = self.order_book_create_function( ) bamboo_relay_active_order_tracker: BambooRelayActiveOrderTracker = BambooRelayActiveOrderTracker( ) bids, asks = bamboo_relay_active_order_tracker.convert_snapshot_message_to_order_book_row( snapshot_msg) bamboo_relay_order_book.apply_snapshot( bids, asks, snapshot_msg.update_id) retval[trading_pair] = BambooRelayOrderBookTrackerEntry( trading_pair, snapshot_timestamp, bamboo_relay_order_book, bamboo_relay_active_order_tracker) self.logger().info( f"Initialized order book for {trading_pair}. " f"{index+1}/{number_of_pairs} completed.") await asyncio.sleep(0.9) except Exception: self.logger().error( f"Error getting snapshot for {trading_pair}. ", exc_info=True) await asyncio.sleep(5.0) return retval
async def get_tracking_pairs(self) -> Dict[str, OrderBookTrackerEntry]: # Get the currently active markets async with aiohttp.ClientSession() as client: trading_pairs: List[str] = await self.get_trading_pairs() retval: Dict[str, OrderBookTrackerEntry] = {} for trading_pair in trading_pairs: try: snapshot: Dict[str, any] = await self.get_snapshot( client, trading_pair) snapshot_timestamp: float = time.time() snapshot_msg: BambooRelayOrderBookMessage = self.order_book_class.snapshot_message_from_exchange( snapshot, snapshot_timestamp, metadata={"symbol": trading_pair}) bamboo_relay_order_book: BambooRelayOrderBook = BambooRelayOrderBook( ) bamboo_relay_active_order_tracker: BambooRelayActiveOrderTracker = BambooRelayActiveOrderTracker( ) bids, asks = bamboo_relay_active_order_tracker.convert_snapshot_message_to_order_book_row( snapshot_msg) bamboo_relay_order_book.apply_snapshot( bids, asks, snapshot_msg.update_id) retval[trading_pair] = BambooRelayOrderBookTrackerEntry( trading_pair, snapshot_timestamp, bamboo_relay_order_book, bamboo_relay_active_order_tracker) await asyncio.sleep(0.7) except Exception: self.logger().error( f"Error getting snapshot for {trading_pair}. ", exc_info=True) return retval