コード例 #1
0
    async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue):
        """
        *required
        Subscribe to diff channel via web socket, and keep the connection open for incoming messages
        :param ev_loop: ev_loop to execute this function in
        :param output: an async queue where the incoming messages are stored
        """
        while True:
            try:
                trading_pairs = self._trading_pairs
                tp_map_mrktid = await self.get_map_marketid()
                marketsDict = dict(zip(tp_map_mrktid.values(), tp_map_mrktid.keys()))
                marketIds = []
                for tp in trading_pairs:
                    marketIds.append(tp_map_mrktid[tp])

                async with websockets.connect(constants.WSS_URL) as ws:
                    ws: websockets.WebSocketClientProtocol = ws
                    subscribe_request: Dict[str, Any] = {
                        "type": "subscribe",
                        "channelId": "order_book",
                        "marketIds": marketIds,
                    }
                    await ws.send(ujson.dumps(subscribe_request))
                    async for raw_msg in self._inner_messages(ws):
                        msg = ujson.loads(raw_msg)
                        msg_type: str = msg.get("type", None)
                        if msg_type is None:
                            raise ValueError(f"Eterbase Websocket message does not contain a type - {msg}")
                        elif msg_type == "error":
                            raise ValueError(f"Eterbase Websocket received error message - {msg['message']}")
                        elif msg_type == "pong":
                            self.logger().debug("Eterbase websocket received event pong - {msg}")
                        elif msg_type == "ob_snapshot":
                            order_book_message: OrderBookMessage = EterbaseOrderBook.snapshot_message_from_exchange(msg, pd.Timestamp.now("UTC").timestamp())
                            output.put_nowait(order_book_message)
                        elif msg_type == "ob_update":
                            msg["trading_pair"] = marketsDict[msg["marketId"]]
                            order_book_message: OrderBookMessage = EterbaseOrderBook.diff_message_from_exchange(msg, pd.Timestamp.now("UTC").timestamp())
                            output.put_nowait(order_book_message)
                        else:
                            raise ValueError(f"Unrecognized Eterbase Websocket message received - {msg}")
            except asyncio.CancelledError:
                raise
            except Exception:
                self.logger().network(
                    "Unexpected error with WebSocket connection.",
                    exc_info=True,
                    app_warning_msg="Unexpected error with WebSocket connection. Retrying in 30 seconds. "
                                    "Check network connection."
                )
                await asyncio.sleep(30.0)
コード例 #2
0
 async def get_new_order_book(self, trading_pair: str) -> OrderBook:
     async with aiohttp.ClientSession() as client:
         td_map_id: Dict[str, str] = await self.get_map_marketid()
         snapshot: Dict[str, any] = await self.get_snapshot(client, trading_pair)
         snapshot_timestamp: float = time.time()
         snapshot_msg: OrderBookMessage = EterbaseOrderBook.snapshot_message_from_exchange(
             snapshot,
             snapshot_timestamp,
             metadata={"trading_pair": trading_pair, "market_id": td_map_id[trading_pair]}
         )
         order_book: OrderBook = self.order_book_create_function()
         active_order_tracker: EterbaseActiveOrderTracker = EterbaseActiveOrderTracker()
         bids, asks = active_order_tracker.convert_snapshot_message_to_order_book_row(snapshot_msg)
         order_book.apply_snapshot(bids, asks, snapshot_msg.update_id)
         return order_book
コード例 #3
0
 async def listen_for_order_book_snapshots(self,
                                           ev_loop: asyncio.BaseEventLoop,
                                           output: asyncio.Queue):
     """
     *required
     Fetches order book snapshots for each trading pair, and use them to update the local order book
     :param ev_loop: ev_loop to execute this function in
     :param output: an async queue where the incoming messages are stored
     """
     while True:
         try:
             trading_pairs: List[str] = self._trading_pairs
             async with aiohttp.ClientSession() as client:
                 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: OrderBookMessage = EterbaseOrderBook.snapshot_message_from_exchange(
                             snapshot,
                             snapshot_timestamp,
                             metadata={"product_id": trading_pair})
                         output.put_nowait(snapshot_msg)
                         self.logger().debug(
                             f"Saved order book snapshot for {trading_pair}"
                         )
                         # Be careful not to go above API rate limits.
                         await asyncio.sleep(5.0)
                     except asyncio.CancelledError:
                         raise
                     except Exception:
                         self.logger().network(
                             "Unexpected error with WebSocket connection.",
                             exc_info=True,
                             app_warning_msg=
                             "Unexpected error with WebSocket connection. Retrying in 5 seconds. "
                             "Check network connection.")
                         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)
コード例 #4
0
    def test_diff_message_not_found(self):
        test_active_order_tracker = self.order_book_tracker._active_order_trackers[test_trading_pair]
        test_order_book: OrderBook = EterbaseOrderBook()

        # receive match message that is not in active orders (should be ignored)
        match_msg_to_ignore: Dict[str, Any] = {
            "type": "o_fill",
            "tradeId": 10,
            "orderId": "ac928c66-ca53-498f-9c13-a110027a60e8",
            "timestamp": int(datetime.now().timestamp() * 1000),
            "marketId": 51,
            "qty": "5.23512",
            "price": "400.23",
            "side": 1
        }
        ignore_msg: EterbaseOrderBookMessage = test_order_book.diff_message_from_exchange(match_msg_to_ignore)
        open_ob_row: OrderBookRow = test_active_order_tracker.convert_diff_message_to_order_book_row(ignore_msg)
        self.assertEqual(open_ob_row, ([], []))
コード例 #5
0
 def setUpClass(cls):
     cls.order_book_tracker: EterbaseOrderBookTracker = EterbaseOrderBookTracker(
         trading_pairs=[test_trading_pair])
     cls.order_book_tracker.order_books[
         test_trading_pair] = EterbaseOrderBook()
コード例 #6
0
    def test_diff_msg_get_added_to_order_book(self):
        test_active_order_tracker = self.order_book_tracker._active_order_trackers["ETHEUR"]

        price = "200"
        order_id = "test_order_id"
        market_id = 51
        size = "1.50"
        remaining_size = "1.00"

        # Test open message diff
        raw_open_message = {
            "type": "o_placed",
            "timestamp": datetime.now().timestamp() * 1000,
            "marketId": market_id,
            "orderId": order_id,
            "limitPrice": price,
            "qty": size,
            "oType": 2,
            "side": 1
        }
        open_message = EterbaseOrderBook.diff_message_from_exchange(raw_open_message)
        self.order_book_tracker._order_book_diff_stream.put_nowait(open_message)
        self.run_parallel(asyncio.sleep(5))

        test_order_book_row = test_active_order_tracker.active_bids[Decimal(price)]
        self.assertEqual(test_order_book_row[order_id]["remaining_size"], size)

        # Test match message diff
        match_size = "0.50"
        raw_match_message = {
            "type": "o_fill",
            "tradeId": 10,
            "orderId": order_id,
            "timestamp": datetime.now().timestamp() * 1000,
            "marketId": market_id,
            "qty": match_size,
            "remainingQty": remaining_size,
            "price": price,
            "side": 1
        }
        match_message = EterbaseOrderBook.diff_message_from_exchange(raw_match_message)

        self.order_book_tracker._order_book_diff_stream.put_nowait(match_message)
        self.run_parallel(asyncio.sleep(5))

        test_order_book_row = test_active_order_tracker.active_bids[Decimal(price)]
        self.assertEqual(Decimal(test_order_book_row[order_id]["remaining_size"]),
                         Decimal(remaining_size))

        # Test done message diff
        raw_done_message = {
            "type": "o_closed",
            "timestamp": datetime.now().timestamp() * 1000,
            "marketId": market_id,
            "limitPrice": price,
            "orderId": order_id,
            "reason": "FILLED",
            "qty": match_size,
            "remainingQty": "1.00",
            "side": 1
        }
        done_message = EterbaseOrderBook.diff_message_from_exchange(raw_done_message)

        self.order_book_tracker._order_book_diff_stream.put_nowait(done_message)
        self.run_parallel(asyncio.sleep(5))

        self.assertTrue(Decimal(price) not in test_active_order_tracker.active_bids)