def simulate_limit_order_fill(market: MockPaperExchange, limit_order: LimitOrder, timestamp: float = 0): quote_currency_traded: Decimal = limit_order.price * limit_order.quantity base_currency_traded: Decimal = limit_order.quantity quote_currency: str = limit_order.quote_currency base_currency: str = limit_order.base_currency trade_event: OrderBookTradeEvent = OrderBookTradeEvent( trading_pair=limit_order.trading_pair, timestamp=timestamp, type=TradeType.BUY if limit_order.is_buy else TradeType.SELL, price=limit_order.price, amount=limit_order.quantity ) market.get_order_book(limit_order.trading_pair).apply_trade(trade_event) if limit_order.is_buy: market.set_balance(quote_currency, market.get_balance(quote_currency) - quote_currency_traded) market.set_balance(base_currency, market.get_balance(base_currency) + base_currency_traded) market.trigger_event(MarketEvent.OrderFilled, OrderFilledEvent( market.current_timestamp, limit_order.client_order_id, limit_order.trading_pair, TradeType.BUY, OrderType.LIMIT, limit_order.price, limit_order.quantity, AddedToCostTradeFee(Decimal(0.0)) )) market.trigger_event(MarketEvent.BuyOrderCompleted, BuyOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, base_currency_traded, quote_currency_traded, OrderType.LIMIT )) else: market.set_balance(quote_currency, market.get_balance(quote_currency) + quote_currency_traded) market.set_balance(base_currency, market.get_balance(base_currency) - base_currency_traded) market.trigger_event(MarketEvent.OrderFilled, OrderFilledEvent( market.current_timestamp, limit_order.client_order_id, limit_order.trading_pair, TradeType.SELL, OrderType.LIMIT, limit_order.price, limit_order.quantity, AddedToCostTradeFee(Decimal(0.0)) )) market.trigger_event(MarketEvent.SellOrderCompleted, SellOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, base_currency_traded, quote_currency_traded, OrderType.LIMIT ))
def simulate_limit_order_fill(market: Market, limit_order: LimitOrder): quote_currency_traded: float = float( float(limit_order.price) * float(limit_order.quantity)) base_currency_traded: float = float(limit_order.quantity) quote_currency: str = limit_order.quote_currency base_currency: str = limit_order.base_currency config: MarketConfig = market.config if limit_order.is_buy: market.set_balance( quote_currency, market.get_balance(quote_currency) - quote_currency_traded) market.set_balance( base_currency, market.get_balance(base_currency) + base_currency_traded) market.trigger_event( MarketEvent.OrderFilled, OrderFilledEvent( market.current_timestamp, limit_order.client_order_id, limit_order.symbol, TradeType.BUY, OrderType.LIMIT, float(limit_order.price), float(limit_order.quantity), TradeFee(0.0) # No fee in backtest market )) market.trigger_event( MarketEvent.BuyOrderCompleted, BuyOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, base_currency if config.buy_fees_asset is AssetType.BASE_CURRENCY else quote_currency, base_currency_traded, quote_currency_traded, 0.0, OrderType.LIMIT)) else: market.set_balance( quote_currency, market.get_balance(quote_currency) + quote_currency_traded) market.set_balance( base_currency, market.get_balance(base_currency) - base_currency_traded) market.trigger_event( MarketEvent.OrderFilled, OrderFilledEvent(market.current_timestamp, limit_order.client_order_id, limit_order.symbol, TradeType.SELL, OrderType.LIMIT, float(limit_order.price), float(limit_order.quantity), TradeFee(0.0))) market.trigger_event( MarketEvent.SellOrderCompleted, SellOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, base_currency if config.sell_fees_asset is AssetType.BASE_CURRENCY else quote_currency, base_currency_traded, quote_currency_traded, 0.0, OrderType.LIMIT))
def simulate_limit_order_fill(market: Market, limit_order: LimitOrder): quote_currency_traded: Decimal = limit_order.price * limit_order.quantity base_currency_traded: Decimal = limit_order.quantity quote_currency: str = limit_order.quote_currency base_currency: str = limit_order.base_currency config: MarketConfig = market.config if limit_order.is_buy: market.set_balance(quote_currency, market.get_balance(quote_currency) - quote_currency_traded) market.set_balance(base_currency, market.get_balance(base_currency) + base_currency_traded) market.trigger_event(MarketEvent.OrderFilled, OrderFilledEvent( market.current_timestamp, limit_order.client_order_id, limit_order.trading_pair, TradeType.BUY, OrderType.LIMIT, limit_order.price, limit_order.quantity, TradeFee(Decimal("0")) )) market.trigger_event(MarketEvent.BuyOrderCompleted, BuyOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, base_currency if config.buy_fees_asset is AssetType.BASE_CURRENCY else quote_currency, base_currency_traded, quote_currency_traded, Decimal("0"), OrderType.LIMIT )) else: market.set_balance(quote_currency, market.get_balance(quote_currency) + quote_currency_traded) market.set_balance(base_currency, market.get_balance(base_currency) - base_currency_traded) market.trigger_event(MarketEvent.OrderFilled, OrderFilledEvent( market.current_timestamp, limit_order.client_order_id, limit_order.trading_pair, TradeType.SELL, OrderType.LIMIT, limit_order.price, limit_order.quantity, TradeFee(Decimal("0")) )) market.trigger_event(MarketEvent.SellOrderCompleted, SellOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, base_currency if config.sell_fees_asset is AssetType.BASE_CURRENCY else quote_currency, base_currency_traded, quote_currency_traded, Decimal("0"), OrderType.LIMIT ))
def simulate_limit_order_fill(market: MockPaperExchange, limit_order: LimitOrder): quote_currency_traded: Decimal = limit_order.price * limit_order.quantity base_currency_traded: Decimal = limit_order.quantity quote_currency: str = limit_order.quote_currency base_currency: str = limit_order.base_currency if limit_order.is_buy: market.set_balance(quote_currency, market.get_balance(quote_currency) - quote_currency_traded) market.set_balance(base_currency, market.get_balance(base_currency) + base_currency_traded) market.trigger_event(MarketEvent.OrderFilled, OrderFilledEvent( market.current_timestamp, limit_order.client_order_id, limit_order.trading_pair, TradeType.BUY, OrderType.LIMIT, limit_order.price, limit_order.quantity, AddedToCostTradeFee(Decimal("0")) )) market.trigger_event(MarketEvent.BuyOrderCompleted, BuyOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, quote_currency, base_currency_traded, quote_currency_traded, Decimal("0"), OrderType.LIMIT )) else: market.set_balance(quote_currency, market.get_balance(quote_currency) + quote_currency_traded) market.set_balance(base_currency, market.get_balance(base_currency) - base_currency_traded) market.trigger_event(MarketEvent.OrderFilled, OrderFilledEvent( market.current_timestamp, limit_order.client_order_id, limit_order.trading_pair, TradeType.SELL, OrderType.LIMIT, limit_order.price, limit_order.quantity, AddedToCostTradeFee(Decimal("0")) )) market.trigger_event(MarketEvent.SellOrderCompleted, SellOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, quote_currency, base_currency_traded, quote_currency_traded, Decimal("0"), OrderType.LIMIT ))
def test_create_order_and_completed(self): recorder = MarketsRecorder(sql=self.manager, markets=[self], config_file_path=self.config_file_path, strategy_name=self.strategy_name) create_event = BuyOrderCreatedEvent( timestamp=1642010000, type=OrderType.LIMIT, trading_pair=self.trading_pair, amount=Decimal(1), price=Decimal(1000), order_id="OID1-1642010000000000", creation_timestamp=1640001112.223, exchange_order_id="EOID1", ) recorder._did_create_order(MarketEvent.BuyOrderCreated.value, self, create_event) complete_event = BuyOrderCompletedEvent( timestamp=1642020000, order_id=create_event.order_id, base_asset=self.base, quote_asset=self.quote, base_asset_amount=create_event.amount, quote_asset_amount=create_event.amount * create_event.price, order_type=create_event.type) recorder._did_complete_order(MarketEvent.BuyOrderCompleted.value, self, complete_event) with self.manager.get_new_session() as session: query = session.query(Order) orders = query.all() order = orders[0] order_status = order.status trade_fills = order.trade_fills self.assertEqual(1, len(orders)) self.assertEqual(self.config_file_path, orders[0].config_file_path) self.assertEqual(create_event.order_id, orders[0].id) self.assertEqual(2, len(order_status)) self.assertEqual(MarketEvent.BuyOrderCreated.name, order_status[0].status) self.assertEqual(MarketEvent.BuyOrderCompleted.name, order_status[1].status) self.assertEqual(0, len(trade_fills))
def simulate_limit_order_fill(market: Market, limit_order: LimitOrder, timestamp: float = 0): quote_currency_traded: Decimal = limit_order.price * limit_order.quantity base_currency_traded: Decimal = limit_order.quantity quote_currency: str = limit_order.quote_currency base_currency: str = limit_order.base_currency config: MarketConfig = market.config trade_event: OrderBookTradeEvent = OrderBookTradeEvent( trading_pair=limit_order.trading_pair, timestamp=timestamp, type=TradeType.BUY if limit_order.is_buy else TradeType.SELL, price=limit_order.price, amount=limit_order.quantity ) market.get_order_book(limit_order.trading_pair).apply_trade(trade_event) if limit_order.is_buy: market.set_balance(quote_currency, market.get_balance(quote_currency) - quote_currency_traded) market.set_balance(base_currency, market.get_balance(base_currency) + base_currency_traded) market.trigger_event(MarketEvent.OrderFilled, OrderFilledEvent( market.current_timestamp, limit_order.client_order_id, limit_order.trading_pair, TradeType.BUY, OrderType.LIMIT, limit_order.price, limit_order.quantity, TradeFee(Decimal(0.0)) )) market.trigger_event(MarketEvent.BuyOrderCompleted, BuyOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, base_currency if config.buy_fees_asset is AssetType.BASE_CURRENCY else quote_currency, base_currency_traded, quote_currency_traded, Decimal(0.0), OrderType.LIMIT )) else: market.set_balance(quote_currency, market.get_balance(quote_currency) + quote_currency_traded) market.set_balance(base_currency, market.get_balance(base_currency) - base_currency_traded) market.trigger_event(MarketEvent.OrderFilled, OrderFilledEvent( market.current_timestamp, limit_order.client_order_id, limit_order.trading_pair, TradeType.SELL, OrderType.LIMIT, limit_order.price, limit_order.quantity, TradeFee(Decimal(0.0)) )) market.trigger_event(MarketEvent.SellOrderCompleted, SellOrderCompletedEvent( market.current_timestamp, limit_order.client_order_id, base_currency, quote_currency, base_currency if config.sell_fees_asset is AssetType.BASE_CURRENCY else quote_currency, base_currency_traded, quote_currency_traded, Decimal(0.0), OrderType.LIMIT ))
async def _process_order_message(self, stream_message: Dict[str, Any]): client_order_id = stream_message["data"]["clientOrderId"] # trading_pair = convert_from_exchange_trading_pair(stream_message["symbol"]) # 1:NEW,2:FILLED,3:PARTIALLY_FILLED,4:CANCELED,5:PARTIALLY_CANCELED order_status = ws_order_status_convert_to_str( stream_message["data"]["status"]) tracked_order = self._in_flight_orders.get(client_order_id, None) if tracked_order is None: return # Update balance in time await self._update_balances() if order_status in {"FILLED", "PARTIALLY_FILLED"}: executed_amount = Decimal(str( stream_message["data"]['quantity'])) - Decimal( str(stream_message["data"]['remainQuantity'])) execute_price = Decimal(str(stream_message["data"]['price'])) execute_amount_diff = executed_amount - tracked_order.executed_amount_base if execute_amount_diff > s_decimal_0: tracked_order.executed_amount_base = executed_amount tracked_order.executed_amount_quote = Decimal( str(stream_message["data"]['amount'])) - Decimal( str(stream_message["data"]['remainAmount'])) current_fee = self.get_fee(tracked_order.base_asset, tracked_order.quote_asset, tracked_order.order_type, tracked_order.trade_type, execute_amount_diff, execute_price) self.logger().info( f"Filled {execute_amount_diff} out of {tracked_order.amount} of " ) self.trigger_event( self.MARKET_ORDER_FILLED_EVENT_TAG, OrderFilledEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.trading_pair, tracked_order.trade_type, tracked_order.order_type, execute_price, execute_amount_diff, current_fee, exchange_trade_id=tracked_order.exchange_order_id)) if order_status == "FILLED": fee_paid, fee_currency = await self.get_deal_detail_fee( tracked_order.exchange_order_id) tracked_order.fee_paid = fee_paid tracked_order.fee_asset = fee_currency tracked_order.last_state = order_status if tracked_order.trade_type is TradeType.BUY: self.logger().info( f"The BUY {tracked_order.order_type} order {tracked_order.client_order_id} has completed " f"according to order delta websocket API.") self.trigger_event( self.MARKET_BUY_ORDER_COMPLETED_EVENT_TAG, BuyOrderCompletedEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.base_asset, tracked_order.quote_asset, tracked_order.fee_asset or tracked_order.quote_asset, tracked_order.executed_amount_base, tracked_order.executed_amount_quote, tracked_order.fee_paid, tracked_order.order_type)) elif tracked_order.trade_type is TradeType.SELL: self.logger().info( f"The SELL {tracked_order.order_type} order {tracked_order.client_order_id} has completed " f"according to order delta websocket API.") self.trigger_event( self.MARKET_SELL_ORDER_COMPLETED_EVENT_TAG, SellOrderCompletedEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.base_asset, tracked_order.quote_asset, tracked_order.fee_asset or tracked_order.quote_asset, tracked_order.executed_amount_base, tracked_order.executed_amount_quote, tracked_order.fee_paid, tracked_order.order_type)) self.stop_tracking_order(tracked_order.client_order_id) return if order_status == "CANCELED" or order_status == "PARTIALLY_CANCELED": tracked_order.last_state = order_status self.logger().info( f"Order {tracked_order.client_order_id} has been cancelled " f"according to order delta websocket API.") self.trigger_event( self.MARKET_ORDER_CANCELLED_EVENT_TAG, OrderCancelledEvent(self.current_timestamp, tracked_order.client_order_id)) self.stop_tracking_order(tracked_order.client_order_id)
async def _update_order_status(self): last_tick = int(self._last_poll_timestamp / self.UPDATE_ORDERS_INTERVAL) current_tick = int(self.current_timestamp / self.UPDATE_ORDERS_INTERVAL) if current_tick > last_tick and len(self._in_flight_orders) > 0: tracked_orders = list(self._in_flight_orders.values()) for tracked_order in tracked_orders: try: exchange_order_id = await tracked_order.get_exchange_order_id( ) try: order_update = await self.get_order_status( exchange_order_id, tracked_order.trading_pair) except MexcAPIError as ex: err_code = ex.error_payload.get("error").get( 'err-code') self.stop_tracking_order(tracked_order.client_order_id) self.logger().info( f"The limit order {tracked_order.client_order_id} " f"has failed according to order status API. - {err_code}" ) self.trigger_event( self.MARKET_ORDER_FAILURE_EVENT_TAG, MarketOrderFailureEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.order_type)) continue if order_update is None: self.logger().network( f"Error fetching status update for the order {tracked_order.client_order_id}: " f"{exchange_order_id}.", app_warning_msg= f"Could not fetch updates for the order {tracked_order.client_order_id}. " f"The order has either been filled or canceled.") continue tracked_order.last_state = order_update['state'] order_status = order_update['state'] new_confirmed_amount = Decimal( order_update['deal_quantity']) execute_amount_diff = new_confirmed_amount - tracked_order.executed_amount_base if execute_amount_diff > s_decimal_0: execute_price = Decimal( Decimal(order_update['deal_amount']) / Decimal(order_update['deal_quantity'])) tracked_order.executed_amount_base = Decimal( order_update['deal_quantity']) tracked_order.executed_amount_quote = Decimal( order_update['deal_amount']) order_filled_event = OrderFilledEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.trading_pair, tracked_order.trade_type, tracked_order.order_type, execute_price, execute_amount_diff, self.get_fee( tracked_order.base_asset, tracked_order.quote_asset, tracked_order.order_type, tracked_order.trade_type, execute_amount_diff, execute_price, ), exchange_trade_id=exchange_order_id) self.logger().info( f"Filled {execute_amount_diff} out of {tracked_order.amount} of the " f"order {tracked_order.client_order_id}.") self.trigger_event(self.MARKET_ORDER_FILLED_EVENT_TAG, order_filled_event) if order_status == "FILLED": fee_paid, fee_currency = await self.get_deal_detail_fee( tracked_order.exchange_order_id) tracked_order.fee_paid = fee_paid tracked_order.fee_asset = fee_currency tracked_order.last_state = order_status self.stop_tracking_order(tracked_order.client_order_id) if tracked_order.trade_type is TradeType.BUY: self.logger().info( f"The BUY {tracked_order.order_type} order {tracked_order.client_order_id} has completed " f"according to order delta restful API.") self.trigger_event( self.MARKET_BUY_ORDER_COMPLETED_EVENT_TAG, BuyOrderCompletedEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.base_asset, tracked_order.quote_asset, tracked_order.fee_asset or tracked_order.quote_asset, tracked_order.executed_amount_base, tracked_order.executed_amount_quote, tracked_order.fee_paid, tracked_order.order_type)) elif tracked_order.trade_type is TradeType.SELL: self.logger().info( f"The SELL {tracked_order.order_type} order {tracked_order.client_order_id} has completed " f"according to order delta restful API.") self.trigger_event( self.MARKET_SELL_ORDER_COMPLETED_EVENT_TAG, SellOrderCompletedEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.base_asset, tracked_order.quote_asset, tracked_order.fee_asset or tracked_order.quote_asset, tracked_order.executed_amount_base, tracked_order.executed_amount_quote, tracked_order.fee_paid, tracked_order.order_type)) continue if order_status == "CANCELED" or order_status == "PARTIALLY_CANCELED": tracked_order.last_state = order_status self.stop_tracking_order(tracked_order.client_order_id) self.logger().info( f"Order {tracked_order.client_order_id} has been cancelled " f"according to order delta restful API.") self.trigger_event( self.MARKET_ORDER_CANCELLED_EVENT_TAG, OrderCancelledEvent(self.current_timestamp, tracked_order.client_order_id)) except Exception as ex: self.logger().error("_update_order_status error ..." + repr(ex), exc_info=True)
def test_non_grouped_hanging_order_and_original_order_removed_when_hanging_order_completed( self): strategy_active_orders = [] newly_created_buy_orders_ids = [ "Order-1234570000000000", "Order-1234570020000000", "Order-1234570040000000", "Order-1234570060000000" ] newly_created_sell_orders_ids = [ "Order-1234570010000000", "Order-1234570030000000", "Order-1234570050000000", "Order-1234570070000000" ] type(self.strategy).active_orders = PropertyMock( return_value=strategy_active_orders) self.strategy.buy_with_specific_market.side_effect = newly_created_buy_orders_ids self.strategy.sell_with_specific_market.side_effect = newly_created_sell_orders_ids buy_order_1 = LimitOrder("Order-1234569960000000", "BTC-USDT", True, "BTC", "USDT", Decimal(101), Decimal(1), creation_timestamp=1234569960000000) sell_order_1 = LimitOrder("Order-1234569970000000", "BTC-USDT", False, "BTC", "USDT", Decimal(110), Decimal(1), creation_timestamp=1234569970000000) self.tracker.add_order(buy_order_1) strategy_active_orders.append(buy_order_1) self.tracker.add_order(sell_order_1) strategy_active_orders.append(sell_order_1) self.tracker.update_strategy_orders_with_equivalent_orders() buy_hanging_order = next( order for order in self.tracker.strategy_current_hanging_orders if order.is_buy) sell_hanging_order = next( order for order in self.tracker.strategy_current_hanging_orders if not order.is_buy) self.assertEqual(buy_order_1.client_order_id, buy_hanging_order.order_id) self.assertEqual(sell_order_1.client_order_id, sell_hanging_order.order_id) self.assertEqual(2, len(self.tracker.original_orders)) self.assertEqual(2, len(self.tracker.strategy_current_hanging_orders)) # Now we simulate the buy hanging order being fully filled strategy_active_orders.remove(buy_order_1) self.tracker._did_complete_buy_order( MarketEvent.BuyOrderCompleted, self, BuyOrderCompletedEvent(timestamp=datetime.now().timestamp(), order_id=buy_order_1.client_order_id, base_asset="BTC", quote_asset="USDT", base_asset_amount=buy_order_1.quantity, quote_asset_amount=buy_order_1.quantity * buy_order_1.price, order_type=OrderType.LIMIT)) self.assertEqual(1, len(self.tracker.strategy_current_hanging_orders)) self.assertNotIn(buy_hanging_order, self.tracker.strategy_current_hanging_orders) self.assertEqual(1, len(self.tracker.original_orders)) self.assertNotIn(buy_order_1, self.tracker.original_orders) self.assertTrue( self.tracker.is_order_id_in_completed_hanging_orders( buy_hanging_order.order_id)) self.assertFalse( self.tracker.is_order_id_in_completed_hanging_orders( sell_hanging_order.order_id))
def test_grouped_hanging_order_and_original_orders_removed_when_hanging_order_completed(self): strategy_active_orders = [] newly_created_buy_orders_ids = ["Order-1234570000000000", "Order-1234570020000000", "Order-1234570040000000", "Order-1234570060000000"] newly_created_sell_orders_ids = ["Order-1234570010000000", "Order-1234570030000000", "Order-1234570050000000", "Order-1234570070000000"] type(self.strategy).active_orders = PropertyMock(return_value=strategy_active_orders) self.strategy.buy_with_specific_market.side_effect = newly_created_buy_orders_ids self.strategy.sell_with_specific_market.side_effect = newly_created_sell_orders_ids buy_order_1 = LimitOrder("Order-1234569960000000", "BTC-USDT", True, "BTC", "USDT", Decimal(101), Decimal(1)) buy_order_2 = LimitOrder("Order-1234569980000000", "BTC-USDT", True, "BTC", "USDT", Decimal(105), Decimal(1)) sell_order_1 = LimitOrder("Order-1234569970000000", "BTC-USDT", False, "BTC", "USDT", Decimal(110), Decimal(1)) sell_order_2 = LimitOrder("Order-1234569990000000", "BTC-USDT", False, "BTC", "USDT", Decimal(115), Decimal(1)) self.tracker.set_aggregation_method(HangingOrdersAggregationType.VOLUME_WEIGHTED) self.tracker.add_order(buy_order_1) strategy_active_orders.append(buy_order_1) self.tracker.add_order(buy_order_2) strategy_active_orders.append(buy_order_2) self.tracker.add_order(sell_order_1) strategy_active_orders.append(sell_order_1) self.tracker.add_order(sell_order_2) strategy_active_orders.append(sell_order_2) self.tracker.update_strategy_orders_with_equivalent_orders() buy_hanging_order = next(order for order in self.tracker.strategy_current_hanging_orders if order.is_buy) sell_hanging_order = next(order for order in self.tracker.strategy_current_hanging_orders if not order.is_buy) strategy_active_orders.remove(buy_order_1) strategy_active_orders.remove(buy_order_2) strategy_active_orders.append(buy_hanging_order) strategy_active_orders.append(sell_hanging_order) self.assertEqual(4, len(self.tracker.original_orders)) self.assertEqual(2, len(self.tracker.strategy_current_hanging_orders)) # Now we simulate the buy hanging order being fully filled strategy_active_orders.remove(buy_hanging_order) self.tracker._did_complete_buy_order(MarketEvent.BuyOrderCompleted, self, BuyOrderCompletedEvent( timestamp=datetime.now().timestamp(), order_id=buy_hanging_order.order_id, base_asset="BTC", quote_asset="USDT", fee_asset="USDT", base_asset_amount=buy_hanging_order.amount, quote_asset_amount=buy_hanging_order.amount * buy_hanging_order.price, fee_amount=Decimal(0), order_type=OrderType.LIMIT)) self.assertEqual(1, len(self.tracker.strategy_current_hanging_orders)) self.assertNotIn(buy_hanging_order, self.tracker.strategy_current_hanging_orders) self.assertEqual(2, len(self.tracker.original_orders)) self.assertTrue(all(not order.is_buy for order in self.tracker.original_orders)) # In this moment the only hanging order in the tracker is the generated by the two sells. # We add a new buy hanging order to test that fully filling the sell hanging order only removes the sells self.tracker.add_order(buy_order_1) strategy_active_orders.append(buy_order_1) self.tracker.update_strategy_orders_with_equivalent_orders() buy_hanging_order = next(order for order in self.tracker.strategy_current_hanging_orders if order.is_buy) strategy_active_orders.remove(buy_order_1) strategy_active_orders.append(buy_hanging_order) self.assertEqual(3, len(self.tracker.original_orders)) self.assertEqual(2, len(self.tracker.strategy_current_hanging_orders)) # Now we simulate the sell hanging order being fully filled strategy_active_orders.remove(sell_hanging_order) self.tracker._did_complete_sell_order(MarketEvent.BuyOrderCompleted, self, BuyOrderCompletedEvent( timestamp=datetime.now().timestamp(), order_id=sell_hanging_order.order_id, base_asset="BTC", quote_asset="USDT", fee_asset="USDT", base_asset_amount=sell_hanging_order.amount, quote_asset_amount=sell_hanging_order.amount * sell_hanging_order.price, fee_amount=Decimal(0), order_type=OrderType.LIMIT)) self.assertEqual(1, len(self.tracker.strategy_current_hanging_orders)) self.assertNotIn(sell_hanging_order, self.tracker.strategy_current_hanging_orders) self.assertEqual(1, len(self.tracker.original_orders)) self.assertTrue(all(order.is_buy for order in self.tracker.original_orders))
def _update_inflight_order(self, tracked_order: BitmexInFlightOrder, event: Dict[str, Any]): trading_pair_multiplier = self._trading_pair_to_multipliers[ tracked_order.trading_pair] event["amount_remaining"] = Decimal(str( event["leavesQty"])) / trading_pair_multiplier.base_multiplier issuable_events: List[MarketEvent] = tracked_order.update(event) # Issue relevent events for (market_event, new_amount, new_price, new_fee) in issuable_events: base, quote = self.split_trading_pair(tracked_order.trading_pair) if market_event == MarketEvent.OrderFilled: self.trigger_event( ORDER_FILLED_EVENT, OrderFilledEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.trading_pair, tracked_order.trade_type, tracked_order.order_type, new_price, new_amount, build_trade_fee(self._domain, True, base, quote, tracked_order.order_type, tracked_order.trade_type, new_amount, new_price), tracked_order.client_order_id)) elif market_event == MarketEvent.OrderCancelled: self.logger().info( f"Successfully cancelled order {tracked_order.client_order_id}" ) self.stop_tracking_order(tracked_order.client_order_id) self.trigger_event( ORDER_CANCELLED_EVENT, OrderCancelledEvent(self.current_timestamp, tracked_order.client_order_id)) elif market_event == MarketEvent.BuyOrderCompleted: self.logger().info( f"The market buy order {tracked_order.client_order_id} has completed " f"according to user stream.") self.trigger_event( BUY_ORDER_COMPLETED_EVENT, BuyOrderCompletedEvent(self.current_timestamp, tracked_order.client_order_id, base, quote, tracked_order.executed_amount_base, tracked_order.executed_amount_quote, tracked_order.order_type, tracked_order.exchange_order_id)) elif market_event == MarketEvent.SellOrderCompleted: self.logger().info( f"The market sell order {tracked_order.client_order_id} has completed " f"according to user stream.") self.trigger_event( SELL_ORDER_COMPLETED_EVENT, SellOrderCompletedEvent( self.current_timestamp, tracked_order.client_order_id, base, quote, tracked_order.executed_amount_base, tracked_order.executed_amount_quote, tracked_order.order_type, tracked_order.exchange_order_id)) # Complete the order if relevent if tracked_order.is_done: self.stop_tracking_order(tracked_order.client_order_id)