def setUp(self) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.base_asset = "BTC" self.quote_asset = "USDT" self.trading_pair = f"{self.base_asset}-{self.quote_asset}" self.ex_trading_pair = f"{self.base_asset}/{self.quote_asset}" self.log_records = [] self.listening_task = None self.async_task: Optional[asyncio.Task] = None self.throttler = AsyncThrottler(CONSTANTS.RATE_LIMITS) self.api_factory = build_api_factory(throttler=self.throttler) self.data_source = AscendExAPIOrderBookDataSource( api_factory=self.api_factory, throttler=self.throttler, trading_pairs=[self.trading_pair]) self.data_source.logger().setLevel(1) self.data_source.logger().addHandler(self) self.mocking_assistant = NetworkMockingAssistant() self.resume_test_event = asyncio.Event() AscendExAPIOrderBookDataSource._trading_pair_symbol_map = bidict( {self.ex_trading_pair: f"{self.base_asset}-{self.quote_asset}"})
async def get_last_traded_prices( cls, trading_pairs: List[str], domain: str = "com", api_factory: Optional[WebAssistantsFactory] = None, throttler: Optional[AsyncThrottler] = None) -> Dict[str, float]: """ Return a dictionary the trading_pair as key and the current price as value for each trading pair passed as parameter :param trading_pairs: list of trading pairs to get the prices for :param domain: which Binance domain we are connecting to (the default value is 'com') :param api_factory: the instance of the web assistant factory to be used when doing requests to the server. If no instance is provided then a new one will be created. :param throttler: the instance of the throttler to use to limit request to the server. If it is not specified the function will create a new one. :return: Dictionary of associations between token pair and its latest price """ local_api_factory = api_factory or build_api_factory() rest_assistant = await local_api_factory.get_rest_assistant() local_throttler = throttler or cls._get_throttler_instance() tasks = [ cls._get_last_traded_price(t_pair, domain, rest_assistant, local_throttler) for t_pair in trading_pairs ] results = await safe_gather(*tasks) return { t_pair: result for t_pair, result in zip(trading_pairs, results) }
async def _init_trading_pair_symbols( cls, domain: str = "com", api_factory: Optional[WebAssistantsFactory] = None, throttler: Optional[AsyncThrottler] = None): """ Initialize mapping of trade symbols in exchange notation to trade symbols in client notation """ mapping = bidict() local_api_factory = api_factory or build_api_factory() rest_assistant = await local_api_factory.get_rest_assistant() local_throttler = throttler or cls._get_throttler_instance() url = binance_utils.public_rest_url( path_url=CONSTANTS.EXCHANGE_INFO_PATH_URL, domain=domain) request = RESTRequest(method=RESTMethod.GET, url=url) try: async with local_throttler.execute_task( limit_id=CONSTANTS.EXCHANGE_INFO_PATH_URL): response: RESTResponse = await rest_assistant.call( request=request) if response.status == 200: data = await response.json() for symbol_data in filter( binance_utils.is_exchange_information_valid, data["symbols"]): mapping[symbol_data[ "symbol"]] = f"{symbol_data['baseAsset']}-{symbol_data['quoteAsset']}" except Exception as ex: cls.logger().error( f"There was an error requesting exchange info ({str(ex)})") cls._trading_pair_symbol_map[domain] = mapping
async def get_all_mid_prices(domain="com") -> Dict[str, Decimal]: """ Returns the mid price of all trading pairs, obtaining the information from the exchange. This functionality is required by the market price strategy. :param domain: Domain to use for the connection with the exchange (either "com" or "us"). Default value is "com" :return: Dictionary with the trading pair as key, and the mid price as value """ local_api_factory = build_api_factory() rest_assistant = await local_api_factory.get_rest_assistant() throttler = BinanceAPIOrderBookDataSource._get_throttler_instance() url = binance_utils.public_rest_url( path_url=CONSTANTS.TICKER_PRICE_CHANGE_PATH_URL, domain=domain) request = RESTRequest(method=RESTMethod.GET, url=url) async with throttler.execute_task( limit_id=CONSTANTS.TICKER_PRICE_CHANGE_PATH_URL): resp: RESTResponse = await rest_assistant.call(request=request) resp_json = await resp.json() ret_val = {} for record in resp_json: try: pair = await BinanceAPIOrderBookDataSource.trading_pair_associated_to_exchange_symbol( symbol=record["symbol"], domain=domain) ret_val[pair] = ((Decimal(record.get("bidPrice", "0")) + Decimal(record.get("askPrice", "0"))) / Decimal("2")) except KeyError: # Ignore results for pairs that are not tracked continue return ret_val
def __init__(self, trading_pairs: List[str], domain="com", api_factory: Optional[WebAssistantsFactory] = None, throttler: Optional[AsyncThrottler] = None): super().__init__(trading_pairs) self._order_book_create_function = lambda: OrderBook() self._domain = domain self._throttler = throttler or self._get_throttler_instance() self._api_factory = api_factory or build_api_factory() self._rest_assistant: Optional[RESTAssistant] = None self._ws_assistant: Optional[WSAssistant] = None self._message_queue: Dict[str, asyncio.Queue] = defaultdict(asyncio.Queue)
def __init__(self, auth: BinanceAuth, domain: str = "com", api_factory: Optional[WebAssistantsFactory] = None, throttler: Optional[AsyncThrottler] = None): super().__init__() self._auth: BinanceAuth = auth self._current_listen_key = None self._last_recv_time: float = 0 self._domain = domain self._throttler = throttler or self._get_throttler_instance() self._api_factory = api_factory or build_api_factory() self._rest_assistant: Optional[RESTAssistant] = None self._ws_assistant: Optional[WSAssistant] = None self._listen_key_initialized_event: asyncio.Event = asyncio.Event() self._last_listen_key_ping_ts = 0