async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue): """ Listen for orderbook diffs using websocket book channel """ while True: async with websockets.connect(constants.WSS_URL) as ws: try: ws: websockets.WebSocketClientProtocol = ws for trading_pair in self._trading_pairs: params: Dict[str, Any] = { "name": "SubscribeOrderBook", "data": k2_utils.convert_to_exchange_trading_pair( trading_pair) } await ws.send(ujson.dumps(params)) async for raw_msg in self._inner_messages(ws): response = ujson.loads(raw_msg) timestamp = int(time.time() * 1e3) if response["method"] == "SubscribeOrderBook": trading_pair = k2_utils.convert_from_exchange_trading_pair( response["pair"]) message: OrderBookMessage = K2OrderBook.snapshot_message_from_exchange( msg=response, timestamp=timestamp, metadata={"trading_pair": trading_pair}) elif response["method"] == "orderbookchanged": data = ujson.loads(response["data"]) trading_pair = k2_utils.convert_from_exchange_trading_pair( data["pair"]) message: OrderBookMessage = K2OrderBook.diff_message_from_exchange( msg=data, timestamp=timestamp, metadata={"trading_pair": trading_pair}) else: # Ignores all other messages continue output.put_nowait(message) 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) finally: await ws.close()
async def get_open_orders(self) -> List[OpenOrder]: result = await self._api_request(method="POST", path_url=constants.GET_OPEN_ORDERS, is_auth_required=True) ret_val = [] for order in result["data"]: # TradeType is not provided by v1/Private/GetOpenOrders endpoint # if order["type"] != "LIMIT": # raise Exception(f"Unsupported order type {order['type']}") ret_val.append( OpenOrder( client_order_id=order["orderid"], trading_pair=k2_utils.convert_from_exchange_trading_pair( order["symbol"]), price=Decimal(str(order["price"])), amount=Decimal(str(order["quantity"])), executed_amount=Decimal(str(order["quantity"])) - Decimal(str(order["leaveqty"])), status=constants.ORDER_STATUS[order["status"]], order_type=OrderType.LIMIT, is_buy=True if order["type"] == "Buy" else False, time=int( time.time() * 1e3 ), # TODO: Check in with K2 for order creation ts, order update ts exchange_order_id=order[ "orderid"] # TODO: Check in with K2 for unique order id )) return ret_val
def update_with_trade_update(self, trade_update: Dict[str, Any]) -> bool: """ Update the InFlightOrder with the trade update from Private/GetHistory API endpoint return: True if the order gets updated successfully otherwise False """ trade_id: str = str(trade_update["id"]) trade_order_id: str = str(trade_update["orderid"]) if trade_order_id != self.exchange_order_id or trade_id in self.trade_id_set: return False self.trade_id_set.add(trade_id) trade_price: Decimal = Decimal(str(trade_update["price"])) trade_amount: Decimal = Decimal(str(trade_update["amount"])) if trade_update["type"] == "Buy": self.executed_amount_base += trade_amount self.executed_amount_quote += trade_price * trade_amount else: self.executed_amount_quote += trade_amount self.executed_amount_base += trade_amount / trade_price self.fee_paid += Decimal(str(trade_update["fee"])) if not self.fee_asset: base, quote = convert_from_exchange_trading_pair( trade_update["symbol"]).split("-") self.fee_asset = base if trade_update["type"] == "Buy" else quote return True
async def fetch_trading_pairs() -> List[str]: async with aiohttp.ClientSession() as client: async with client.get(f"{constants.REST_URL}{constants.GET_TRADING_PAIRS}", timeout=10) as response: if response.status == 200: try: data: Dict[str, Any] = await response.json() return [k2_utils.convert_from_exchange_trading_pair(item["symbol"]) for item in data["data"]] except Exception: pass # Do nothing if the request fails -- there will be no autocomplete for kucoin trading pairs return []
def _format_trading_rules(self, data: Dict[str, Any]) -> Dict[str, TradingRule]: """ Converts json API response into a dictionary of trading rules. :param instruments_info: The json API response :return A dictionary of trading rules. Response Example: { "success": true, "data": [ { "symbol": "BEAM/BTC", "buymakerfee": 0.00000000, "sellmakerfee": 0.00000000, "buytakerfee": 0.00200000, "selltakerfee": 0.00020000, "mintradevalue": 0.00010000, "decimals": { "price": 8, "amount": 8 } },... """ result = {} for trading_pair_stat in data["data"]: try: trading_pair = k2_utils.convert_from_exchange_trading_pair( trading_pair_stat["symbol"]) price_decimals = Decimal( str(trading_pair_stat["decimals"]["price"])) quantity_decimals = Decimal( str(trading_pair_stat["decimals"]["amount"])) min_trade_value = Decimal( str(trading_pair_stat["mintradevalue"])) # E.g. a price decimal of 2 means 0.01 incremental. price_step = Decimal("1") / Decimal( str(math.pow(10, price_decimals))) quantity_step = Decimal("1") / Decimal( str(math.pow(10, quantity_decimals))) result[trading_pair] = TradingRule( trading_pair, min_price_increment=price_step, min_base_amount_increment=quantity_step, min_order_value=min_trade_value) except Exception: self.logger().error( f"Error parsing the trading pair rule {data}. Skipping.", exc_info=True) raise return result