def test_market_became_wider(self):  # TODO
        self.clock.backtest_til(self.start_timestamp + 5)

        bid_order: LimitOrder = self.strategy.active_bids[0][1]
        ask_order: LimitOrder = self.strategy.active_asks[0][1]
        self.assertEqual(Decimal("0.99452"), bid_order.price)
        self.assertEqual(Decimal("1.0056"), ask_order.price)
        self.assertEqual(Decimal("3.0"), bid_order.quantity)
        self.assertEqual(Decimal("3.0"), ask_order.quantity)

        self.taker_market.trigger_event(
            MarketEvent.BuyOrderCreated,
            BuyOrderCreatedEvent(self.start_timestamp + 5, OrderType.LIMIT,
                                 bid_order.trading_pair, bid_order.quantity,
                                 bid_order.price, bid_order.client_order_id))

        self.taker_market.trigger_event(
            MarketEvent.SellOrderCreated,
            SellOrderCreatedEvent(self.start_timestamp + 5, OrderType.LIMIT,
                                  ask_order.trading_pair, ask_order.quantity,
                                  ask_order.price, ask_order.client_order_id))

        self.simulate_order_book_widening(self.taker_data.order_book, 0.99,
                                          1.01)

        self.clock.backtest_til(self.start_timestamp + 100)

        self.assertEqual(2, len(self.cancel_order_logger.event_log))
        self.assertEqual(1, len(self.strategy.active_bids))
        self.assertEqual(1, len(self.strategy.active_asks))

        bid_order = self.strategy.active_bids[0][1]
        ask_order = self.strategy.active_asks[0][1]
        self.assertEqual(Decimal("0.98457"), bid_order.price)
        self.assertEqual(Decimal("1.0156"), ask_order.price)
Ejemplo n.º 2
0
    def test_sell_order_created_event_creates_order_record(self):
        recorder = MarketsRecorder(sql=self.manager,
                                   markets=[self],
                                   config_file_path=self.config_file_path,
                                   strategy_name=self.strategy_name)

        event = SellOrderCreatedEvent(
            timestamp=int(time.time()),
            type=OrderType.LIMIT,
            trading_pair=self.trading_pair,
            amount=Decimal(1),
            price=Decimal(1000),
            order_id="OID1",
            creation_timestamp=1640001112.223,
            exchange_order_id="EOID1",
        )

        recorder._did_create_order(MarketEvent.SellOrderCreated.value, self,
                                   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(event.order_id, orders[0].id)
        self.assertEqual(1640001112223, orders[0].creation_timestamp)
        self.assertEqual(1, len(order_status))
        self.assertEqual(MarketEvent.SellOrderCreated.name,
                         order_status[0].status)
        self.assertEqual(0, len(trade_fills))
    async def execute_sell(
            self,
            order_id: str,
            trading_pair: str,
            amount: Decimal,
            order_type: OrderType,
            price: Optional[Decimal] = Decimal("NaN"),
    ):
        try:
            await self.execute_order(TradeType.SELL, order_id, trading_pair,
                                     amount, order_type, price)
            tracked_order = self.in_flight_orders.get(order_id)
            if tracked_order is not None:
                self.trigger_event(
                    SELL_ORDER_CREATED_EVENT,
                    SellOrderCreatedEvent(
                        now(),
                        order_type,
                        trading_pair,
                        Decimal(amount),
                        Decimal(price),
                        order_id,
                        tracked_order.creation_timestamp,
                    ),
                )

        except ValueError as e:
            # never tracked, so no need to stop tracking
            self.trigger_event(
                ORDER_FAILURE_EVENT,
                MarketOrderFailureEvent(now(), order_id, order_type))
            self.logger().warning(
                f"Failed to place {order_id} on bitmex. {str(e)}")
Ejemplo n.º 4
0
    def test_top_depth_tolerance(self):  # TODO
        self.clock.remove_iterator(self.strategy)
        self.clock.add_iterator(self.strategy_with_top_depth_tolerance)
        self.clock.backtest_til(self.start_timestamp + 5)
        bid_order: LimitOrder = self.strategy_with_top_depth_tolerance.active_bids[
            0][1]
        ask_order: LimitOrder = self.strategy_with_top_depth_tolerance.active_asks[
            0][1]

        self.taker_market.trigger_event(
            MarketEvent.BuyOrderCreated,
            BuyOrderCreatedEvent(
                self.start_timestamp + 5,
                OrderType.LIMIT,
                bid_order.trading_pair,
                bid_order.quantity,
                bid_order.price,
                bid_order.client_order_id,
                bid_order.creation_timestamp * 1e-6,
            ))

        self.taker_market.trigger_event(
            MarketEvent.SellOrderCreated,
            SellOrderCreatedEvent(
                self.start_timestamp + 5,
                OrderType.LIMIT,
                ask_order.trading_pair,
                ask_order.quantity,
                ask_order.price,
                ask_order.client_order_id,
                ask_order.creation_timestamp * 1e-6,
            ))

        self.assertEqual(Decimal("0.99451"), bid_order.price)
        self.assertEqual(Decimal("1.0055"), ask_order.price)
        self.assertEqual(Decimal("3.0"), bid_order.quantity)
        self.assertEqual(Decimal("3.0"), ask_order.quantity)

        self.simulate_order_book_widening(
            self.taker_market.order_books[self.taker_trading_pairs[0]], 0.99,
            1.01)

        self.clock.backtest_til(self.start_timestamp + 100)

        self.assertEqual(2, len(self.cancel_order_logger.event_log))
        self.assertEqual(
            1, len(self.strategy_with_top_depth_tolerance.active_bids))
        self.assertEqual(
            1, len(self.strategy_with_top_depth_tolerance.active_asks))

        bid_order = self.strategy_with_top_depth_tolerance.active_bids[0][1]
        ask_order = self.strategy_with_top_depth_tolerance.active_asks[0][1]
        self.assertEqual(Decimal("0.98457"), bid_order.price)
        self.assertEqual(Decimal("1.0155"), ask_order.price)
Ejemplo n.º 5
0
    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))
    def test_order_fills_after_cancellation(self):  # TODO
        self.clock.backtest_til(self.start_timestamp + 5)
        bid_order: LimitOrder = self.strategy.active_bids[0][1]
        ask_order: LimitOrder = self.strategy.active_asks[0][1]
        self.assertEqual(Decimal("0.99452"), bid_order.price)
        self.assertEqual(Decimal("1.0056"), ask_order.price)
        self.assertEqual(Decimal("3.0"), bid_order.quantity)
        self.assertEqual(Decimal("3.0"), ask_order.quantity)

        self.taker_market.trigger_event(
            MarketEvent.BuyOrderCreated,
            BuyOrderCreatedEvent(self.start_timestamp + 5, OrderType.LIMIT,
                                 bid_order.trading_pair, bid_order.quantity,
                                 bid_order.price, bid_order.client_order_id))

        self.taker_market.trigger_event(
            MarketEvent.SellOrderCreated,
            SellOrderCreatedEvent(self.start_timestamp + 5, OrderType.LIMIT,
                                  ask_order.trading_pair, ask_order.quantity,
                                  ask_order.price, ask_order.client_order_id))

        self.simulate_order_book_widening(self.taker_data.order_book, 0.99,
                                          1.01)

        self.clock.backtest_til(self.start_timestamp + 10)

        self.assertEqual(2, len(self.cancel_order_logger.event_log))
        self.assertEqual(1, len(self.strategy.active_bids))
        self.assertEqual(1, len(self.strategy.active_asks))

        bid_order = self.strategy.active_bids[0][1]
        ask_order = self.strategy.active_asks[0][1]
        self.assertEqual(Decimal("0.98457"), bid_order.price)
        self.assertEqual(Decimal("1.0156"), ask_order.price)

        self.clock.backtest_til(self.start_timestamp + 20)
        self.simulate_limit_order_fill(self.maker_market, bid_order)
        self.simulate_limit_order_fill(self.maker_market, ask_order)

        self.clock.backtest_til(self.start_timestamp + 25)
        fill_events: List[
            OrderFilledEvent] = self.taker_order_fill_logger.event_log
        bid_hedges: List[OrderFilledEvent] = [
            evt for evt in fill_events if evt.trade_type is TradeType.SELL
        ]
        ask_hedges: List[OrderFilledEvent] = [
            evt for evt in fill_events if evt.trade_type is TradeType.BUY
        ]
        self.assertEqual(1, len(bid_hedges))
        self.assertEqual(1, len(ask_hedges))
        self.assertGreater(
            self.maker_market.get_balance(self.maker_trading_pairs[2]) +
            self.taker_market.get_balance(self.taker_trading_pairs[2]),
            Decimal("10"),
        )
        self.assertEqual(2, len(self.taker_order_fill_logger.event_log))
        taker_fill1: OrderFilledEvent = self.taker_order_fill_logger.event_log[
            0]
        self.assertEqual(TradeType.SELL, taker_fill1.trade_type)
        self.assertAlmostEqual(Decimal("0.9895"), taker_fill1.price)
        self.assertAlmostEqual(Decimal("3.0"), taker_fill1.amount)
        taker_fill2: OrderFilledEvent = self.taker_order_fill_logger.event_log[
            1]
        self.assertEqual(TradeType.BUY, taker_fill2.trade_type)
        self.assertAlmostEqual(Decimal("1.0105"), taker_fill2.price)
        self.assertAlmostEqual(Decimal("3.0"), taker_fill2.amount)
    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.BuyOrderCreated,
                BuyOrderCreatedEvent(market.current_timestamp, OrderType.LIMIT,
                                     limit_order.trading_pair,
                                     limit_order.quantity, limit_order.price,
                                     limit_order.client_order_id))
            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.BuyOrderCreated,
                SellOrderCreatedEvent(market.current_timestamp,
                                      OrderType.LIMIT,
                                      limit_order.trading_pair,
                                      limit_order.quantity, limit_order.price,
                                      limit_order.client_order_id))
            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,
                ),
            )
Ejemplo n.º 8
0
    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.BuyOrderCreated,
                BuyOrderCreatedEvent(market.current_timestamp, OrderType.LIMIT,
                                     limit_order.trading_pair,
                                     limit_order.quantity, limit_order.price,
                                     limit_order.client_order_id,
                                     limit_order.creation_timestamp * 1e-6))
            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,
                    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.BuyOrderCreated,
                SellOrderCreatedEvent(
                    market.current_timestamp,
                    OrderType.LIMIT,
                    limit_order.trading_pair,
                    limit_order.quantity,
                    limit_order.price,
                    limit_order.client_order_id,
                    limit_order.creation_timestamp * 1e-6,
                ))
            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,
                    base_currency_traded,
                    quote_currency_traded,
                    OrderType.LIMIT,
                ),
            )