async def _create_order(self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, price: Decimal = s_decimal_0, order_type: OrderType = OrderType.MARKET): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (also called client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param price: The order price :param order_type: The order type """ trading_rule: TradingRule = self._trading_rules[trading_pair] trading_pair_ids: Dict[ str, int] = await self._order_book_tracker.data_source.get_instrument_ids( ) try: amount: Decimal = self.quantize_order_amount(trading_pair, amount) if amount < trading_rule.min_order_size: raise ValueError( f"{trade_type.name} order amount {amount} is lower than the minimum order size " f"{trading_rule.min_order_size}.") params = { "InstrumentId": trading_pair_ids[trading_pair], "OMSId": 1, "AccountId": await self.initialized_account_id(), "ClientOrderId": int(order_id), "Side": 0 if trade_type == TradeType.BUY else 1, "Quantity": amount, "TimeInForce": 1, # GTC } if order_type.is_limit_type(): price: Decimal = self.quantize_order_price(trading_pair, price) params.update({ "OrderType": 2, # Limit "LimitPrice": price, }) else: params.update({ "OrderType": 1 # Market }) self.start_tracking_order(order_id, None, trading_pair, trade_type, price, amount, order_type) send_order_results = await self._api_request( method="POST", path_url=CONSTANTS.SEND_ORDER_PATH_URL, data=params, is_auth_required=True) if send_order_results["status"] == "Rejected": raise ValueError( f"Order is rejected by the API. " f"Parameters: {params} Error Msg: {send_order_results['errormsg']}" ) exchange_order_id = str(send_order_results["OrderId"]) tracked_order = self._in_flight_orders.get(order_id) if tracked_order is not None: self.logger().info( f"Created {order_type.name} {trade_type.name} order {order_id} for " f"{amount} {trading_pair}.") tracked_order.update_exchange_order_id(exchange_order_id) except asyncio.CancelledError: raise except Exception as e: self.stop_tracking_order(order_id) self.trigger_event( MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type)) self.logger().network( f"Error submitting {trade_type.name} {order_type.name} order to NDAX for " f"{amount} {trading_pair} {price}. Error: {str(e)}", exc_info=True, app_warning_msg="Error submitting order to NDAX. ")
async def _create_order(self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Decimal): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (also called client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param order_type: The order type :param price: The order price """ if not order_type.is_limit_type(): raise Exception(f"Unsupported order type: {order_type}") trading_rule = self._trading_rules[trading_pair] amount = self.quantize_order_amount(trading_pair, amount) price = self.quantize_order_price(trading_pair, price) if amount < trading_rule.min_order_size: raise ValueError( f"Buy order amount {amount} is lower than the minimum order size " f"{trading_rule.min_order_size}.") api_params = { "instrument_name": crypto_com_utils.convert_to_exchange_trading_pair(trading_pair), "side": trade_type.name, "type": "LIMIT", "price": f"{price:f}", "quantity": f"{amount:f}", "client_oid": order_id } if order_type is OrderType.LIMIT_MAKER: api_params["exec_inst"] = "POST_ONLY" self.start_tracking_order(order_id, None, trading_pair, trade_type, price, amount, order_type) try: order_result = await self._api_request("post", "private/create-order", api_params, True) exchange_order_id = str(order_result["result"]["order_id"]) tracked_order = self._in_flight_orders.get(order_id) if tracked_order is not None: self.logger().info( f"Created {order_type.name} {trade_type.name} order {order_id} for " f"{amount} {trading_pair}.") tracked_order.update_exchange_order_id(exchange_order_id) event_tag = MarketEvent.BuyOrderCreated if trade_type is TradeType.BUY else MarketEvent.SellOrderCreated event_class = BuyOrderCreatedEvent if trade_type is TradeType.BUY else SellOrderCreatedEvent self.trigger_event( event_tag, event_class(self.current_timestamp, order_type, trading_pair, amount, price, order_id)) except asyncio.CancelledError: raise except Exception as e: self.stop_tracking_order(order_id) self.logger().network( f"Error submitting {trade_type.name} {order_type.name} order to Crypto.com for " f"{amount} {trading_pair} " f"{price}.", exc_info=True, app_warning_msg=str(e)) self.trigger_event( MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type))
async def execute_sell(self, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Optional[Decimal] = s_decimal_0): trading_rule = self._trading_rules[trading_pair] if not order_type.is_limit_type(): self.trigger_event( self.MARKET_ORDER_FAILURE_EVENT_TAG, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type)) raise Exception(f"Unsupported order type: {order_type}") decimal_price = self.quantize_order_price(trading_pair, price) decimal_amount = self.quantize_order_amount(trading_pair, amount, decimal_price) if decimal_price * decimal_amount < trading_rule.min_notional_size: self.trigger_event( self.MARKET_ORDER_FAILURE_EVENT_TAG, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type)) raise ValueError( f"Sell order amount {decimal_amount} is lower than the notional size " ) try: exchange_order_id = await self.place_order(order_id, trading_pair, decimal_amount, False, order_type, decimal_price) self.start_tracking_order(order_id=order_id, exchange_order_id=exchange_order_id, trading_pair=trading_pair, order_type=order_type, trade_type=TradeType.SELL, price=decimal_price, amount=decimal_amount) tracked_order = self._in_flight_orders.get(order_id) if tracked_order is not None: self.logger().info( f"Created {order_type.name.upper()} sell order {order_id} for {decimal_amount} {trading_pair}." ) self.trigger_event( self.MARKET_SELL_ORDER_CREATED_EVENT_TAG, SellOrderCreatedEvent(self.current_timestamp, order_type, trading_pair, decimal_amount, decimal_price, order_id)) except asyncio.CancelledError: raise except Exception as ex: self.stop_tracking_order(order_id) order_type_str = order_type.name.lower() self.logger().network( f"Error submitting sell {order_type_str} order to Mexc for " f"{decimal_amount} {trading_pair} " f"{decimal_price if order_type is OrderType.LIMIT else ''}." f"{decimal_price}." + ",ex:" + repr(ex), exc_info=True, app_warning_msg= "Failed to submit sell order to Mexc. Check API key and network connection." ) self.trigger_event( self.MARKET_ORDER_FAILURE_EVENT_TAG, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type))
async def _create_order(self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Decimal): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (also called client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param order_type: The order type :param price: The order price """ if not order_type.is_limit_type(): raise Exception(f"Unsupported order type: {order_type}") trading_rule = self._trading_rules[trading_pair] amount = self.quantize_order_amount(trading_pair, amount) price = self.quantize_order_price(trading_pair, price) if amount < trading_rule.min_order_size: raise ValueError(f"Buy order amount {amount} is lower than the minimum order size " f"{trading_rule.min_order_size}.") order_type_str = order_type.name.lower().split("_")[0] api_params = {"market": convert_to_exchange_trading_pair(trading_pair), "side": trade_type.name.lower(), "ord_type": order_type_str, "price": f"{price:f}", "volume": f"{amount:f}", } # if order_type is OrderType.LIMIT_MAKER: # api_params["postOnly"] = "true" self.start_tracking_order(order_id, None, trading_pair, trade_type, price, amount, order_type) try: order_result = await self._api_request("POST", Constants.ENDPOINT["ORDER_CREATE"], api_params, True) exchange_order_id = str(order_result["id"]) tracked_order = self._in_flight_orders.get(order_id) if tracked_order is not None: self.logger().info(f"Created {order_type.name} {trade_type.name} order {order_id} for " f"{amount} {trading_pair}.") tracked_order.update_exchange_order_id(exchange_order_id) if trade_type is TradeType.BUY: event_tag = MarketEvent.BuyOrderCreated event_cls = BuyOrderCreatedEvent else: event_tag = MarketEvent.SellOrderCreated event_cls = SellOrderCreatedEvent self.trigger_event(event_tag, event_cls(self.current_timestamp, order_type, trading_pair, amount, price, order_id)) except asyncio.CancelledError: raise except AltmarketsAPIError as e: error_reason = e.error_payload.get('error', {}).get('message') self.stop_tracking_order(order_id) self.logger().network( f"Error submitting {trade_type.name} {order_type.name} order to {Constants.EXCHANGE_NAME} for " f"{amount} {trading_pair} {price} - {error_reason}.", exc_info=True, app_warning_msg=(f"Error submitting order to {Constants.EXCHANGE_NAME} - {error_reason}.") ) self.trigger_event(MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type))
async def _create_order(self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Decimal): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (aka client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param order_type: The order type :param price: The order price """ if not order_type.is_limit_type(): raise Exception(f"Unsupported order type: {order_type}") ascend_ex_trading_rule = self._ascend_ex_trading_rules[trading_pair] amount = self.quantize_order_amount(trading_pair, amount) price = self.quantize_order_price(trading_pair, price) try: # ascend_ex has a unique way of determening if the order has enough "worth" to be posted # see https://ascendex.github.io/ascendex-pro-api/#place-order notional = Decimal(price * amount) if notional < ascend_ex_trading_rule.minNotional or notional > ascend_ex_trading_rule.maxNotional: raise ValueError( f"Notional amount {notional} is not withing the range of {ascend_ex_trading_rule.minNotional}-{ascend_ex_trading_rule.maxNotional}." ) # TODO: check balance [exchange_order_id, timestamp ] = ascend_ex_utils.gen_exchange_order_id(self._account_uid, order_id) api_params = { "id": exchange_order_id, "time": timestamp, "symbol": ascend_ex_utils.convert_to_exchange_trading_pair(trading_pair), "orderPrice": f"{price:f}", "orderQty": f"{amount:f}", "orderType": "limit", "side": trade_type.name } self.start_tracking_order(order_id, exchange_order_id, trading_pair, trade_type, price, amount, order_type) await self._api_request("post", "cash/order", api_params, True, force_auth_path_url="order") tracked_order = self._in_flight_orders.get(order_id) if tracked_order is not None: self.logger().info( f"Created {order_type.name} {trade_type.name} order {order_id} for " f"{amount} {trading_pair}.") event_tag = MarketEvent.BuyOrderCreated if trade_type is TradeType.BUY else MarketEvent.SellOrderCreated event_class = BuyOrderCreatedEvent if trade_type is TradeType.BUY else SellOrderCreatedEvent self.trigger_event( event_tag, event_class(self.current_timestamp, order_type, trading_pair, amount, price, order_id, exchange_order_id=exchange_order_id)) except asyncio.CancelledError: raise except Exception as e: self.stop_tracking_order(order_id) self.logger().network( f"Error submitting {trade_type.name} {order_type.name} order to AscendEx for " f"{amount} {trading_pair} " f"{price}.", exc_info=True, app_warning_msg=str(e)) self.trigger_event( MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type))
async def _create_order(self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Decimal): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (aka client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param order_type: The order type :param price: The order price """ if not order_type.is_limit_type(): raise Exception(f"Unsupported order type: {order_type}") amount = self.quantize_order_amount(trading_pair, amount) price = self.quantize_order_price(trading_pair, price) if amount <= s_decimal_0: raise ValueError("Order amount must be greater than zero.") try: timestamp = ascend_ex_utils.get_ms_timestamp() api_params = { "id": order_id, "time": timestamp, "symbol": ascend_ex_utils.convert_to_exchange_trading_pair(trading_pair), "orderPrice": f"{price:f}", "orderQty": f"{amount:f}", "orderType": "limit", "side": "buy" if trade_type == TradeType.BUY else "sell", "respInst": "ACCEPT", } self.start_tracking_order(order_id, None, trading_pair, trade_type, price, amount, order_type) resp = await self._api_request(method="post", path_url=CONSTANTS.ORDER_PATH_URL, data=api_params, is_auth_required=True, force_auth_path_url="order") exchange_order_id = str(resp["data"]["info"]["orderId"]) tracked_order: AscendExInFlightOrder = self._in_flight_orders.get( order_id) tracked_order.update_exchange_order_id(exchange_order_id) if resp["data"]["status"] == "Ack": # Ack status means the server has received the request return tracked_order.update_status(resp["data"]["info"]["status"]) if tracked_order.is_failure: raise Exception( f'Failed to create an order, reason: {resp["data"]["info"]["errorCode"]}' ) self.logger().info( f"Created {order_type.name} {trade_type.name} order {order_id} for " f"{amount} {trading_pair}.") self.trigger_order_created_event(tracked_order) except asyncio.CancelledError: raise except Exception: self.stop_tracking_order(order_id) msg = f"Error submitting {trade_type.name} {order_type.name} order to AscendEx for " \ f"{amount} {trading_pair} " \ f"{price}." self.logger().network(msg, exc_info=True, app_warning_msg=msg) self.trigger_event( MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type))
async def _create_order(self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Decimal): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (also called client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param order_type: The order type :param price: The order price """ if not order_type.is_limit_type(): raise Exception(f"Unsupported order type: {order_type}") trading_rule = self._trading_rules[trading_pair] amount = self.quantize_order_amount(trading_pair, amount) price = self.quantize_order_price(trading_pair, price) if amount < trading_rule.min_order_size: raise ValueError( f"Order amount {amount} is lower than the minimum order size " f"{trading_rule.min_order_size}.") api_params = { "tempid": order_id, "symbol": k2_utils.convert_to_exchange_trading_pair(trading_pair), "price": f"{price:f}", "quantity": f"{amount:f}", "type": trade_type.name.lower( ), # `type` parameter here refers to Side i.e. Buy or Sell } self.start_tracking_order(order_id, None, trading_pair, trade_type, price, amount, order_type) try: order_result = await self._api_request( method="POST", path_url=constants.PLACE_ORDER, data=api_params, is_auth_required=True) exchange_order_id = str(order_result["data"]["orderids"][0]["id"]) tracked_order = self._in_flight_orders.get(order_id) if tracked_order is not None: self.logger().info( f"Created {order_type.name} {trade_type.name} order {order_id} for " f"{amount} {trading_pair}.") tracked_order.update_exchange_order_id(exchange_order_id) event_tag = MarketEvent.BuyOrderCreated if trade_type is TradeType.BUY else MarketEvent.SellOrderCreated event_class = BuyOrderCreatedEvent if trade_type is TradeType.BUY else SellOrderCreatedEvent self.trigger_event( event_tag, event_class(self.current_timestamp, order_type, trading_pair, amount, price, order_id)) except asyncio.CancelledError: raise except Exception as e: self.stop_tracking_order(order_id) self.logger().network( f"Error submitting {trade_type.name} {order_type.name} order to K2 for " f"{amount} {trading_pair} " f"{price}.", exc_info=True, app_warning_msg=str(e)) self.trigger_event( MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type))
async def _create_order(self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Decimal): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (also called client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param order_type: The order type :param price: The order price """ if not order_type.is_limit_type(): raise Exception(f"Unsupported order type: {order_type}") trading_rule = self._trading_rules[trading_pair] amount = self.quantize_order_amount(trading_pair, amount) price = self.quantize_order_price(trading_pair, price) try: if amount < trading_rule.min_order_size: raise ValueError(f"{trade_type.name} order amount {amount} is lower than the minimum order size " f"{trading_rule.min_order_size}.") order_value: Decimal = amount * price if order_value < trading_rule.min_order_value: raise ValueError(f"{trade_type.name} order value {order_value} is lower than the minimum order value " f"{trading_rule.min_order_value}") body_params = { "market_id": trading_pair, "type": "limit", # ProBit Order Types ["limit", "market"} "side": trade_type.name.lower(), # ProBit Order Sides ["buy", "sell"] "time_in_force": "gtc", # gtc = Good-Til-Cancelled "limit_price": str(price), "quantity": str(amount), "client_order_id": order_id } self.start_tracking_order(order_id, None, trading_pair, trade_type, price, amount, order_type ) order_result = await self._api_request( method="POST", path_url=CONSTANTS.NEW_ORDER_URL, data=body_params, is_auth_required=True ) exchange_order_id = str(order_result["data"]["id"]) tracked_order = self._in_flight_orders.get(order_id) if tracked_order is not None: self.logger().info(f"Created {order_type.name} {trade_type.name} order {order_id} for " f"{amount} {trading_pair}.") tracked_order.update_exchange_order_id(exchange_order_id) event_tag = MarketEvent.BuyOrderCreated if trade_type is TradeType.BUY else MarketEvent.SellOrderCreated event_class = BuyOrderCreatedEvent if trade_type is TradeType.BUY else SellOrderCreatedEvent self.trigger_event(event_tag, event_class( self.current_timestamp, order_type, trading_pair, amount, price, order_id )) except asyncio.CancelledError: raise except Exception as e: self.stop_tracking_order(order_id) self.logger().network( f"Error submitting {trade_type.name} {order_type.name} order to ProBit for " f"{amount} {trading_pair} " f"{price}.", exc_info=True, app_warning_msg=str(e) ) self.trigger_event(MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type))
async def _create_order(self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Decimal): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (also called client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param order_type: The order type :param price: The order price """ if not order_type.is_limit_type(): raise Exception(f"Unsupported order type: {order_type}") trading_rule = self._trading_rules[trading_pair] amount = self.quantize_order_amount(trading_pair, amount) price = self.quantize_order_price(trading_pair, price) if amount < trading_rule.min_order_size: self.logger().warning( f"{trade_type.name.title()} order amount {amount} is lower than the minimum order size " f"{trading_rule.min_order_size}.") else: order_type_str = order_type.name.lower().split("_")[0] api_params = { "text": order_id, "currency_pair": convert_to_exchange_trading_pair(trading_pair), "side": trade_type.name.lower(), "type": order_type_str, "price": f"{price:f}", "amount": f"{amount:f}", } self.start_tracking_order(order_id, None, trading_pair, trade_type, price, amount, order_type) try: order_result = await self._api_request( "POST", CONSTANTS.ORDER_CREATE_PATH_URL, api_params, True) if order_result.get('status') in { "cancelled", "expired", "failed" }: raise GateIoAPIError({ 'label': 'ORDER_REJECTED', 'message': 'Order rejected.' }) else: exchange_order_id = str(order_result["id"]) tracked_order = self._in_flight_orders.get(order_id) if tracked_order is not None: self.logger().info( f"Created {order_type.name} {trade_type.name} order {order_id} for " f"{amount} {trading_pair}.") tracked_order.update_exchange_order_id( exchange_order_id) if trade_type is TradeType.BUY: event_tag = MarketEvent.BuyOrderCreated event_cls = BuyOrderCreatedEvent else: event_tag = MarketEvent.SellOrderCreated event_cls = SellOrderCreatedEvent self.trigger_event( event_tag, event_cls(self.current_timestamp, order_type, trading_pair, amount, price, order_id, exchange_order_id)) except asyncio.CancelledError: raise except GateIoAPIError as e: error_reason = e.error_message self.stop_tracking_order(order_id) self.logger().network( f"Error submitting {trade_type.name} {order_type.name} order to {CONSTANTS.EXCHANGE_NAME} for " f"{amount} {trading_pair} {price} - {error_reason}.", exc_info=True, app_warning_msg= (f"Error submitting order to {CONSTANTS.EXCHANGE_NAME} - {error_reason}." )) self.trigger_event( MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type))
async def _create_order( self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Decimal, ): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (aka client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param order_type: The order type :param price: The order price """ if not order_type.is_limit_type(): raise Exception(f"Unsupported order type: {order_type}") amount = self.quantize_order_amount(trading_pair, amount) price = self.quantize_order_price(trading_pair, price) if amount <= s_decimal_0: raise ValueError("Order amount must be greater than zero.") try: timestamp = ascend_ex_utils.get_ms_timestamp() # Order UUID is strictly used to enable AscendEx to construct a unique(still questionable) exchange_order_id order_uuid = f"{ascend_ex_utils.HBOT_BROKER_ID}-{ascend_ex_utils.uuid32()}"[:32] api_params = { "id": order_uuid, "time": timestamp, "symbol": ascend_ex_utils.convert_to_exchange_trading_pair(trading_pair), "orderPrice": f"{price:f}", "orderQty": f"{amount:f}", "orderType": "limit", "side": "buy" if trade_type == TradeType.BUY else "sell", "respInst": "ACCEPT", } self.start_tracking_order( order_id=order_id, trading_pair=trading_pair, trade_type=trade_type, price=price, amount=amount, order_type=order_type, ) try: resp = await self._api_request( method="post", path_url=CONSTANTS.ORDER_PATH_URL, data=api_params, is_auth_required=True, force_auth_path_url="order", ) resp_status = resp["data"]["status"].upper() order_data = resp["data"]["info"] if resp_status == "ACK": # Ack request status means the server has received the request return order_update = None if resp_status == "ACCEPT": order_update: OrderUpdate = OrderUpdate( client_order_id=order_id, exchange_order_id=str(order_data["orderId"]), trading_pair=trading_pair, update_timestamp=order_data["lastExecTime"], new_state=OrderState.OPEN, ) elif resp_status == "DONE": order_update: OrderUpdate = OrderUpdate( client_order_id=order_id, exchange_order_id=str(order_data["orderId"]), trading_pair=trading_pair, update_timestamp=order_data["lastExecTime"], new_state=CONSTANTS.ORDER_STATE[order_data["status"]], fill_price=Decimal(order_data["avgPx"]), executed_amount_base=Decimal(order_data["cumFilledQty"]), executed_amount_quote=Decimal(order_data["avgPx"]) * Decimal(order_data["cumFilledQty"]), fee_asset=order_data["feeAsset"], cumulative_fee_paid=Decimal(order_data["cumFee"]), ) elif resp_status == "ERR": order_update: OrderUpdate = OrderUpdate( client_order_id=order_id, exchange_order_id=str(order_data["orderId"]), trading_pair=trading_pair, update_timestamp=order_data["lastExecTime"], new_state=OrderState.FAILED, ) self._in_flight_order_tracker.process_order_update(order_update) except IOError: self.logger().exception(f"The request to create the order {order_id} failed") self.stop_tracking_order(order_id) except asyncio.CancelledError: raise except Exception: msg = (f"Error submitting {trade_type.name} {order_type.name} order to AscendEx for " f"{amount} {trading_pair} {price}.") self.logger().exception(msg)
async def _create_order(self, trade_type: TradeType, order_id: str, trading_pair: str, amount: Decimal, order_type: OrderType, price: Decimal): """ Calls create-order API end point to place an order, starts tracking the order and triggers order created event. :param trade_type: BUY or SELL :param order_id: Internal order id (aka client_order_id) :param trading_pair: The market to place order :param amount: The order amount (in base token value) :param order_type: The order type :param price: The order price """ if not order_type.is_limit_type(): raise Exception(f"Unsupported order type: {order_type}") amount = self.quantize_order_amount(trading_pair, amount) price = self.quantize_order_price(trading_pair, price) if amount <= s_decimal_0: raise ValueError("Order amount must be greater than zero.") try: # TODO: check balance [exchange_order_id, timestamp ] = ascend_ex_utils.gen_exchange_order_id(self._account_uid, order_id) api_params = { "id": exchange_order_id, "time": timestamp, "symbol": ascend_ex_utils.convert_to_exchange_trading_pair(trading_pair), "orderPrice": f"{price:f}", "orderQty": f"{amount:f}", "orderType": "limit", "side": trade_type.name } self.start_tracking_order(order_id, exchange_order_id, trading_pair, trade_type, price, amount, order_type) await self._api_request(method="post", path_url="cash/order", params=api_params, is_auth_required=True, force_auth_path_url="order") tracked_order = self._in_flight_orders.get(order_id) if tracked_order is not None: self.logger().info( f"Created {order_type.name} {trade_type.name} order {order_id} for " f"{amount} {trading_pair}.") event_tag = MarketEvent.BuyOrderCreated if trade_type is TradeType.BUY else MarketEvent.SellOrderCreated event_class = BuyOrderCreatedEvent if trade_type is TradeType.BUY else SellOrderCreatedEvent self.trigger_event( event_tag, event_class(self.current_timestamp, order_type, trading_pair, amount, price, order_id, exchange_order_id=exchange_order_id)) except asyncio.CancelledError: raise except Exception as e: self.stop_tracking_order(order_id) self.logger().network( f"Error submitting {trade_type.name} {order_type.name} order to AscendEx for " f"{amount} {trading_pair} " f"{price}.", exc_info=True, app_warning_msg=str(e)) self.trigger_event( MarketEvent.OrderFailure, MarketOrderFailureEvent(self.current_timestamp, order_id, order_type))