Ejemplo n.º 1
0
    def _generate_external_order_status(self, instrument: Instrument,
                                        data: Dict[str, Any]) -> None:
        client_id_str = data.get("clientId")
        price = data.get("price")
        created_at = int(
            pd.to_datetime(data["createdAt"], utc=True).to_datetime64())
        report = OrderStatusReport(
            account_id=self.account_id,
            instrument_id=InstrumentId(Symbol(data["market"]), FTX_VENUE),
            client_order_id=ClientOrderId(client_id_str)
            if client_id_str is not None else None,
            venue_order_id=VenueOrderId(str(data["id"])),
            order_side=OrderSide.BUY
            if data["side"] == "buy" else OrderSide.SELL,
            order_type=parse_order_type(data=data, price_str="price"),
            time_in_force=TimeInForce.IOC if data["ioc"] else TimeInForce.GTC,
            order_status=OrderStatus.ACCEPTED,
            price=instrument.make_price(price) if price is not None else None,
            quantity=instrument.make_qty(data["size"]),
            filled_qty=instrument.make_qty(0),
            avg_px=None,
            post_only=data["postOnly"],
            reduce_only=data["reduceOnly"],
            report_id=self._uuid_factory.generate(),
            ts_accepted=created_at,
            ts_last=created_at,
            ts_init=self._clock.timestamp_ns(),
        )

        self._send_order_status_report(report)
Ejemplo n.º 2
0
 async def _submit_stop_limit_order(
     self,
     order: StopLimitOrder,
     position: Optional[Position],
 ) -> None:
     order_type = "stop"
     if position is not None:
         if order.is_buy and order.trigger_price < position.avg_px_open:
             order_type = "take_profit"
         elif order.is_sell and order.trigger_price > position.avg_px_open:
             order_type = "take_profit"
     response = await self._http_client.place_trigger_order(
         market=order.instrument_id.symbol.value,
         side=OrderSideParser.to_str_py(order.side).lower(),
         size=str(order.quantity),
         order_type=order_type,
         client_id=order.client_order_id.value,
         price=str(order.price),
         trigger_price=str(order.trigger_price),
         reduce_only=order.is_reduce_only,
     )
     self.generate_order_accepted(
         strategy_id=order.strategy_id,
         instrument_id=order.instrument_id,
         client_order_id=order.client_order_id,
         venue_order_id=VenueOrderId(str(response["id"])),
         ts_event=self._clock.timestamp_ns(),
     )
Ejemplo n.º 3
0
def parse_trade_report_http(
    account_id: AccountId,
    instrument_id: InstrumentId,
    data: BinanceFuturesAccountTrade,
    report_id: UUID4,
    ts_init: int,
) -> TradeReport:
    return TradeReport(
        account_id=account_id,
        instrument_id=instrument_id,
        venue_order_id=VenueOrderId(str(data.orderId)),
        venue_position_id=PositionId(
            f"{instrument_id}-{data.positionSide.value}"),
        trade_id=TradeId(str(data.id)),
        order_side=OrderSide[data.side.value],
        last_qty=Quantity.from_str(data.qty),
        last_px=Price.from_str(data.price),
        commission=Money(data.commission,
                         Currency.from_str(data.commissionAsset)),
        liquidity_side=LiquiditySide.MAKER
        if data.maker else LiquiditySide.TAKER,
        report_id=report_id,
        ts_event=millis_to_nanos(data.time),
        ts_init=ts_init,
    )
    def test_serialize_and_deserialize_order_filled_events(self):
        # Arrange
        event = OrderFilled(
            self.account_id,
            ClientOrderId("O-123456"),
            VenueOrderId("1"),
            ExecutionId("E123456"),
            PositionId("T123456"),
            StrategyId("S-001"),
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity(100000, precision=0),
            Price(1.00000, precision=5),
            AUDUSD_SIM.quote_currency,
            Money(0, USD),
            LiquiditySide.TAKER,
            0,
            uuid4(),
            0,
        )

        # Act
        serialized = self.serializer.serialize(event)
        deserialized = self.serializer.deserialize(serialized)

        # Assert
        assert deserialized == event
Ejemplo n.º 5
0
    def event_order_filled(
        order,
        instrument,
        strategy_id=None,
        account_id=None,
        venue_order_id=None,
        execution_id=None,
        position_id=None,
        last_qty=None,
        last_px=None,
        liquidity_side=LiquiditySide.TAKER,
        ts_filled_ns=0,
        account=None,
    ) -> OrderFilled:
        if strategy_id is None:
            strategy_id = order.strategy_id
        if account_id is None:
            account_id = order.account_id
            if account_id is None:
                account_id = TestStubs.account_id()
        if venue_order_id is None:
            venue_order_id = VenueOrderId("1")
        if execution_id is None:
            execution_id = ExecutionId(order.client_order_id.value.replace("O", "E"))
        if position_id is None:
            position_id = order.position_id
        if last_px is None:
            last_px = Price.from_str(f"{1:.{instrument.price_precision}f}")
        if last_qty is None:
            last_qty = order.quantity
        if account is None:
            account = TestStubs.cash_account()

        commission = account.calculate_commission(
            instrument=instrument,
            last_qty=order.quantity,
            last_px=last_px,
            liquidity_side=liquidity_side,
        )

        return OrderFilled(
            trader_id=TestStubs.trader_id(),
            strategy_id=strategy_id,
            account_id=account_id,
            instrument_id=instrument.id,
            client_order_id=order.client_order_id,
            venue_order_id=venue_order_id,
            execution_id=execution_id,
            position_id=position_id,
            order_side=order.side,
            order_type=order.type,
            last_qty=last_qty,
            last_px=last_px or order.price,
            currency=instrument.quote_currency,
            commission=commission,
            liquidity_side=liquidity_side,
            ts_event=ts_filled_ns,
            event_id=UUID4(),
            ts_init=0,
        )
    def test_add_order_state_report(self):
        # Arrange
        report = ExecutionMassStatus(
            client_id=ClientId("IB"),
            account_id=TestStubs.account_id(),
            timestamp_ns=0,
        )

        venue_order_id = VenueOrderId("1")
        order_report = OrderStatusReport(
            client_order_id=ClientOrderId("O-123456"),
            venue_order_id=venue_order_id,
            order_state=OrderState.REJECTED,
            filled_qty=Quantity.zero(),
            timestamp_ns=0,
        )

        # Act
        report.add_order_report(order_report)

        # Assert
        assert report.order_reports()[venue_order_id] == order_report
        assert (
            repr(report)
            == "ExecutionMassStatus(client_id=IB, account_id=SIM-000, ts_recv_ns=0, order_reports={VenueOrderId('1'): OrderStatusReport(client_order_id=O-123456, venue_order_id=1, order_state=REJECTED, filled_qty=0, ts_recv_ns=0)}, exec_reports={}, position_reports={})"  # noqa
        )
        assert (
            repr(order_report)
            == "OrderStatusReport(client_order_id=O-123456, venue_order_id=1, order_state=REJECTED, filled_qty=0, ts_recv_ns=0)"  # noqa
        )
    def test_serialize_and_deserialize_order_partially_filled_events(self):
        # Arrange
        event = OrderFilled(
            self.account_id,
            ClientOrderId("O-123456"),
            VenueOrderId("1"),
            ExecutionId("E123456"),
            PositionId("T123456"),
            StrategyId("S", "001"),
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity(50000),
            Price("1.00000"),
            Quantity(50000),
            Quantity(50000),
            AUDUSD_SIM.quote_currency,
            AUDUSD_SIM.is_inverse,
            Money(0, USD),
            LiquiditySide.MAKER,
            0,
            uuid4(),
            0,
        )

        # Act
        serialized = self.serializer.serialize(event)
        deserialized = self.serializer.deserialize(serialized)

        # Assert
        self.assertEqual(deserialized, event)
Ejemplo n.º 8
0
    def test_order_canceled_event_to_from_dict_and_str_repr(self):
        # Arrange
        uuid = UUID4()
        event = OrderCanceled(
            trader_id=TraderId("TRADER-001"),
            strategy_id=StrategyId("SCALPER-001"),
            account_id=AccountId("SIM", "000"),
            instrument_id=InstrumentId(Symbol("BTC/USDT"), Venue("BINANCE")),
            client_order_id=ClientOrderId("O-2020872378423"),
            venue_order_id=VenueOrderId("123456"),
            ts_event=0,
            event_id=uuid,
            ts_init=0,
        )

        # Act, Assert
        assert OrderCanceled.from_dict(OrderCanceled.to_dict(event)) == event
        assert (
            str(event) ==
            "OrderCanceled(account_id=SIM-000, instrument_id=BTC/USDT.BINANCE, client_order_id=O-2020872378423, venue_order_id=123456, ts_event=0)"  # noqa
        )
        assert (
            repr(event) ==
            f"OrderCanceled(trader_id=TRADER-001, strategy_id=SCALPER-001, account_id=SIM-000, instrument_id=BTC/USDT.BINANCE, client_order_id=O-2020872378423, venue_order_id=123456, event_id={uuid}, ts_event=0, ts_init=0)"  # noqa
        )
async def generate_trades_list(
        self,
        venue_order_id: VenueOrderId,
        symbol: Symbol,
        since: datetime = None) -> List[ExecutionReport]:
    filled = self.client().betting.list_cleared_orders(
        bet_ids=[venue_order_id], )
    if not filled["clearedOrders"]:
        self._log.warn(f"Found no existing order for {venue_order_id}")
        return []
    fill = filled["clearedOrders"][0]
    timestamp_ns = millis_to_nanos(
        pd.Timestamp(fill["lastMatchedDate"]).timestamp())
    return [
        ExecutionReport(
            client_order_id=self.
            venue_order_id_to_client_order_id[venue_order_id],
            venue_order_id=VenueOrderId(fill["betId"]),
            execution_id=ExecutionId(fill["lastMatchedDate"]),
            last_qty=Quantity.from_str(str(
                fill["sizeSettled"])),  # TODO: Possibly incorrect precision
            last_px=Price.from_str(str(
                fill["priceMatched"])),  # TODO: Possibly incorrect precision
            commission=None,  # Can be None
            liquidity_side=LiquiditySide.NONE,
            ts_filled_ns=timestamp_ns,
            timestamp_ns=timestamp_ns,
        )
    ]
Ejemplo n.º 10
0
    def test_modify_order_command_to_from_dict_and_str_repr(self):
        # Arrange
        uuid = self.uuid_factory.generate()

        command = ModifyOrder(
            trader_id=TraderId("TRADER-001"),
            strategy_id=StrategyId("S-001"),
            instrument_id=AUDUSD_SIM.id,
            client_order_id=ClientOrderId("O-123456"),
            venue_order_id=VenueOrderId("001"),
            price=Price.from_str("1.00000"),
            trigger=Price.from_str("1.00010"),
            quantity=Quantity.from_int(100000),
            command_id=uuid,
            ts_init=self.clock.timestamp_ns(),
        )

        # Act, Assert
        assert ModifyOrder.from_dict(ModifyOrder.to_dict(command)) == command
        assert (
            str(command) ==
            "ModifyOrder(instrument_id=AUD/USD.SIM, client_order_id=O-123456, venue_order_id=001, quantity=100_000, price=1.00000, trigger=1.00010)"  # noqa
        )
        assert (
            repr(command) ==
            f"ModifyOrder(trader_id=TRADER-001, strategy_id=S-001, instrument_id=AUD/USD.SIM, client_order_id=O-123456, venue_order_id=001, quantity=100_000, price=1.00000, trigger=1.00010, command_id={uuid}, ts_init=0)"  # noqa
        )
Ejemplo n.º 11
0
    def test_cancel_order_when_order_does_not_exist_then_denies(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy()
        strategy.register(
            trader_id=self.trader_id,
            portfolio=self.portfolio,
            msgbus=self.msgbus,
            cache=self.cache,
            clock=self.clock,
            logger=self.logger,
        )

        cancel = CancelOrder(
            self.trader_id,
            strategy.id,
            AUDUSD_SIM.id,
            ClientOrderId("1"),
            VenueOrderId("1"),
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        # Act
        self.risk_engine.execute(cancel)

        # Assert
        assert self.exec_client.calls == ["_start"]
        assert self.risk_engine.command_count == 1
        assert self.exec_engine.command_count == 0
Ejemplo n.º 12
0
    async def test_on_order_modify(self):
        # Arrange
        self.instrument_setup()
        nautilus_order = TestExecStubs.limit_order()
        self.exec_client._client_order_id_to_strategy_id[
            nautilus_order.client_order_id] = TestIdStubs.strategy_id()
        self.exec_client._venue_order_id_to_client_order_id[
            1] = nautilus_order.client_order_id
        order = IBExecTestStubs.ib_order(permId=1)
        order.permId = 1
        self.cache.add_order(nautilus_order, None)
        trade = IBExecTestStubs.trade_submitted(order=order)

        # Act
        with patch.object(self.exec_client, "generate_order_updated") as mock:
            self.exec_client._on_order_modify(trade)

        # Assert
        name, args, kwargs = mock.mock_calls[0]
        expected = {
            "client_order_id": nautilus_order.client_order_id,
            "instrument_id": self.instrument.id,
            "price": Price.from_str("0.01"),
            "quantity": Quantity.from_str("1"),
            "strategy_id": TestIdStubs.strategy_id(),
            "trigger_price": None,
            "ts_event": 1646449588378175000,
            "venue_order_id": VenueOrderId("189868420"),
            "venue_order_id_modified": False,
        }
        assert kwargs == expected
Ejemplo n.º 13
0
    def test_update_order_when_no_order_found_denies(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy()
        strategy.register(
            trader_id=self.trader_id,
            portfolio=self.portfolio,
            msgbus=self.msgbus,
            cache=self.cache,
            clock=self.clock,
            logger=self.logger,
        )

        modify = ModifyOrder(
            self.trader_id,
            strategy.id,
            AUDUSD_SIM.id,
            ClientOrderId("invalid"),
            VenueOrderId("1"),
            Quantity.from_int(100000),
            Price.from_str("1.00010"),
            None,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        # Act
        self.risk_engine.execute(modify)

        # Assert
        assert self.exec_client.calls == ["_start"]
        assert self.risk_engine.command_count == 1
        assert self.exec_engine.command_count == 0
Ejemplo n.º 14
0
def parse_order_status_http(
    account_id: AccountId,
    instrument: Instrument,
    data: Dict[str, Any],
    report_id: UUID4,
    ts_init: int,
) -> OrderStatusReport:
    client_id_str = data.get("clientId")
    price = data.get("price")
    avg_px = data["avgFillPrice"]
    created_at = int(
        pd.to_datetime(data["createdAt"], utc=True).to_datetime64())
    return OrderStatusReport(
        account_id=account_id,
        instrument_id=InstrumentId(Symbol(data["market"]), FTX_VENUE),
        client_order_id=ClientOrderId(client_id_str)
        if client_id_str is not None else None,
        venue_order_id=VenueOrderId(str(data["id"])),
        order_side=OrderSide.BUY if data["side"] == "buy" else OrderSide.SELL,
        order_type=parse_order_type(data=data, price_str="price"),
        time_in_force=TimeInForce.IOC if data["ioc"] else TimeInForce.GTC,
        order_status=parse_order_status(data),
        price=instrument.make_price(price) if price is not None else None,
        quantity=instrument.make_qty(data["size"]),
        filled_qty=instrument.make_qty(data["filledSize"]),
        avg_px=Decimal(str(avg_px)) if avg_px is not None else None,
        post_only=data["postOnly"],
        reduce_only=data["reduceOnly"],
        report_id=report_id,
        ts_accepted=created_at,
        ts_last=created_at,
        ts_init=ts_init,
    )
Ejemplo n.º 15
0
async def test_update_order(mocker, execution_client, exec_engine, risk_engine):
    exec_engine.register_risk_engine(risk_engine)

    # Add sample order to the cache
    order = BetfairTestStubs.make_order(exec_engine)
    order.apply(BetfairTestStubs.event_order_submitted(order=order))
    order.apply(
        BetfairTestStubs.event_order_accepted(
            order=order, venue_order_id=VenueOrderId("229435133092")
        )
    )
    exec_engine.cache.add_order(order, PositionId("1"))

    mock_replace_orders = mocker.patch(
        "betfairlightweight.endpoints.betting.Betting.replace_orders",
        return_value=BetfairTestStubs.place_orders_success(),
    )

    # Actual test
    update = BetfairTestStubs.update_order_command(
        instrument_id=order.instrument_id, client_order_id=order.client_order_id
    )
    execution_client.update_order(update)
    await asyncio.sleep(0.1)
    expected = {
        "customer_ref": update.id.value.replace("-", ""),
        "instructions": [{"betId": "229435133092", "newPrice": 1.35}],
        "market_id": "1.179082386",
    }
    mock_replace_orders.assert_called_with(**expected)
Ejemplo n.º 16
0
    async def _submit_order(self, command: SubmitOrder) -> None:
        self._log.debug(f"Received submit_order {command}")

        self.generate_order_submitted(
            instrument_id=command.instrument_id,
            strategy_id=command.strategy_id,
            client_order_id=command.order.client_order_id,
            ts_event=self._clock.timestamp_ns(),
        )
        self._log.debug("Generated _generate_order_submitted")

        instrument = self._cache.instrument(command.instrument_id)
        PyCondition.not_none(instrument, "instrument")
        client_order_id = command.order.client_order_id

        place_order = order_submit_to_betfair(command=command, instrument=instrument)
        try:
            result = await self._client.place_orders(**place_order)
        except Exception as exc:
            if isinstance(exc, BetfairAPIError):
                await self.on_api_exception(exc=exc)
            self._log.warning(f"Submit failed: {exc}")
            self.generate_order_rejected(
                strategy_id=command.strategy_id,
                instrument_id=command.instrument_id,
                client_order_id=client_order_id,
                reason="client error",  # type: ignore
                ts_event=self._clock.timestamp_ns(),
            )
            return

        self._log.debug(f"result={result}")
        for report in result["instructionReports"]:
            if result["status"] == "FAILURE":
                reason = f"{result['errorCode']}: {report['errorCode']}"
                self._log.warning(f"Submit failed - {reason}")
                self.generate_order_rejected(
                    strategy_id=command.strategy_id,
                    instrument_id=command.instrument_id,
                    client_order_id=client_order_id,
                    reason=reason,  # type: ignore
                    ts_event=self._clock.timestamp_ns(),
                )
                self._log.debug("Generated _generate_order_rejected")
                return
            else:
                venue_order_id = VenueOrderId(report["betId"])
                self._log.debug(
                    f"Matching venue_order_id: {venue_order_id} to client_order_id: {client_order_id}"
                )
                self.venue_order_id_to_client_order_id[venue_order_id] = client_order_id  # type: ignore
                self.generate_order_accepted(
                    strategy_id=command.strategy_id,
                    instrument_id=command.instrument_id,
                    client_order_id=client_order_id,
                    venue_order_id=venue_order_id,  # type: ignore
                    ts_event=self._clock.timestamp_ns(),
                )
                self._log.debug("Generated _generate_order_accepted")
Ejemplo n.º 17
0
 def _prefill_venue_order_id_to_client_order_id(self, update):
     order_ids = [
         update["id"]
         for market in update.get("oc", [])
         for order in market.get("orc", [])
         for update in order.get("uo", [])
     ]
     return {VenueOrderId(oid): ClientOrderId(str(i + 1)) for i, oid in enumerate(order_ids)}
    def test_add_order_status_reports(self):
        # Arrange
        report_id1 = UUID4()
        mass_status = ExecutionMassStatus(
            client_id=ClientId("IB"),
            account_id=AccountId("IB", "U123456789"),
            venue=Venue("IDEALPRO"),
            report_id=report_id1,
            ts_init=0,
        )

        venue_order_id = VenueOrderId("2")
        report_id2 = UUID4()
        report = OrderStatusReport(
            account_id=AccountId("IB", "U123456789"),
            instrument_id=AUDUSD_IDEALPRO,
            client_order_id=ClientOrderId("O-123456"),
            order_list_id=OrderListId("1"),
            venue_order_id=venue_order_id,
            order_side=OrderSide.SELL,
            order_type=OrderType.STOP_LIMIT,
            contingency_type=ContingencyType.OCO,
            time_in_force=TimeInForce.DAY,
            expire_time=None,
            order_status=OrderStatus.REJECTED,
            price=Price.from_str("0.90090"),
            trigger_price=Price.from_str("0.90100"),
            trigger_type=TriggerType.DEFAULT,
            limit_offset=None,
            trailing_offset=Decimal("0.00010"),
            offset_type=TrailingOffsetType.PRICE,
            quantity=Quantity.from_int(1_000_000),
            filled_qty=Quantity.from_int(0),
            display_qty=None,
            avg_px=None,
            post_only=True,
            reduce_only=False,
            cancel_reason="SOME_REASON",
            report_id=report_id2,
            ts_accepted=1_000_000,
            ts_triggered=0,
            ts_last=2_000_000,
            ts_init=3_000_000,
        )

        # Act
        mass_status.add_order_reports([report])

        # Assert
        assert mass_status.order_reports()[venue_order_id] == report
        assert (
            repr(mass_status)
            == f"ExecutionMassStatus(client_id=IB, account_id=IB-U123456789, venue=IDEALPRO, order_reports={{VenueOrderId('2'): OrderStatusReport(account_id=IB-U123456789, instrument_id=AUD/USD.IDEALPRO, client_order_id=O-123456, order_list_id=1, venue_order_id=2, order_side=SELL, order_type=STOP_LIMIT, contingency_type=OCO, time_in_force=DAY, expire_time=None, order_status=REJECTED, price=0.90090, trigger_price=0.90100, trigger_type=DEFAULT, limit_offset=None, trailing_offset=0.00010, offset_type=PRICE, quantity=1_000_000, filled_qty=0, leaves_qty=1_000_000, display_qty=None, avg_px=None, post_only=True, reduce_only=False, cancel_reason=SOME_REASON, report_id={report_id2}, ts_accepted=1000000, ts_triggered=0, ts_last=2000000, ts_init=3000000)}}, trade_reports={{}}, position_reports={{}}, report_id={report_id1}, ts_init=0)"  # noqa
        )
        assert (
            repr(report)
            == f"OrderStatusReport(account_id=IB-U123456789, instrument_id=AUD/USD.IDEALPRO, client_order_id=O-123456, order_list_id=1, venue_order_id=2, order_side=SELL, order_type=STOP_LIMIT, contingency_type=OCO, time_in_force=DAY, expire_time=None, order_status=REJECTED, price=0.90090, trigger_price=0.90100, trigger_type=DEFAULT, limit_offset=None, trailing_offset=0.00010, offset_type=PRICE, quantity=1_000_000, filled_qty=0, leaves_qty=1_000_000, display_qty=None, avg_px=None, post_only=True, reduce_only=False, cancel_reason=SOME_REASON, report_id={report_id2}, ts_accepted=1000000, ts_triggered=0, ts_last=2000000, ts_init=3000000)"  # noqa
        )
Ejemplo n.º 19
0
    def test_position_filled_with_buy_order_returns_expected_attributes(self):
        # Arrange
        order = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        fill = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("1.00001"),
        )

        last = Price.from_str("1.00050")

        # Act
        position = Position(instrument=AUDUSD_SIM, fill=fill)

        # Assert
        assert position.symbol == AUDUSD_SIM.id.symbol
        assert position.venue == AUDUSD_SIM.id.venue
        assert not position.is_opposite_side(fill.order_side)
        assert not position != position  # Equality operator test
        assert position.from_order == ClientOrderId(
            "O-19700101-000000-000-001-1")
        assert position.quantity == Quantity.from_int(100000)
        assert position.peak_qty == Quantity.from_int(100000)
        assert position.entry == OrderSide.BUY
        assert position.side == PositionSide.LONG
        assert position.ts_opened == 0
        assert position.duration_ns == 0
        assert position.avg_px_open == Decimal("1.00001")
        assert position.event_count == 1
        assert position.client_order_ids == [order.client_order_id]
        assert position.venue_order_ids == [VenueOrderId("1")]
        assert position.execution_ids == [
            ExecutionId("E-19700101-000000-000-001-1")
        ]
        assert position.last_execution_id == ExecutionId(
            "E-19700101-000000-000-001-1")
        assert position.id == PositionId("P-123456")
        assert len(position.events) == 1
        assert position.is_long
        assert not position.is_short
        assert position.is_open
        assert not position.is_closed
        assert position.realized_points == 0
        assert position.realized_return == 0
        assert position.realized_pnl == Money(-2.00, USD)
        assert position.unrealized_pnl(last) == Money(49.00, USD)
        assert position.total_pnl(last) == Money(47.00, USD)
        assert position.commissions() == [Money(2.00, USD)]
        assert repr(
            position) == "Position(LONG 100_000 AUD/USD.SIM, id=P-123456)"
Ejemplo n.º 20
0
    def test_update_order_when_already_completed_then_denies(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy()
        strategy.register(
            trader_id=self.trader_id,
            portfolio=self.portfolio,
            msgbus=self.msgbus,
            cache=self.cache,
            clock=self.clock,
            logger=self.logger,
        )

        order = strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00010"),
        )

        submit = SubmitOrder(
            self.trader_id,
            strategy.id,
            None,
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        self.risk_engine.execute(submit)

        self.exec_engine.process(TestStubs.event_order_submitted(order))
        self.exec_engine.process(TestStubs.event_order_accepted(order))
        self.exec_engine.process(
            TestStubs.event_order_filled(order, AUDUSD_SIM))

        modify = ModifyOrder(
            self.trader_id,
            strategy.id,
            order.instrument_id,
            order.client_order_id,
            VenueOrderId("1"),
            order.quantity,
            Price.from_str("1.00010"),
            None,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        # Act
        self.risk_engine.execute(modify)

        # Assert
        assert self.exec_client.calls == ["_start", "submit_order"]
        assert self.risk_engine.command_count == 2
        assert self.exec_engine.command_count == 1
Ejemplo n.º 21
0
    def test_position_filled_with_buy_order_returns_expected_attributes(self):
        # Arrange
        order = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        fill = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("1.00001"),
        )

        last = Price.from_str("1.00050")

        # Act
        position = Position(instrument=AUDUSD_SIM, fill=fill)

        # Assert
        assert position.symbol == AUDUSD_SIM.id.symbol
        assert position.venue == AUDUSD_SIM.id.venue
        assert not position.is_opposite_side(fill.order_side)
        self.assertFalse(position != position)  # Equality operator test
        self.assertEqual(ClientOrderId("O-19700101-000000-000-001-1"),
                         position.from_order)
        self.assertEqual(Quantity.from_int(100000), position.quantity)
        self.assertEqual(Quantity.from_int(100000), position.peak_qty)
        self.assertEqual(OrderSide.BUY, position.entry)
        self.assertEqual(PositionSide.LONG, position.side)
        self.assertEqual(0, position.opened_timestamp_ns)
        self.assertEqual(0, position.open_duration_ns)
        self.assertEqual(Decimal("1.00001"), position.avg_px_open)
        self.assertEqual(1, position.event_count)
        self.assertEqual([order.client_order_id], position.client_order_ids)
        self.assertEqual([VenueOrderId("1")], position.venue_order_ids)
        self.assertEqual([ExecutionId("E-19700101-000000-000-001-1")],
                         position.execution_ids)
        self.assertEqual(ExecutionId("E-19700101-000000-000-001-1"),
                         position.last_execution_id)
        self.assertEqual(PositionId("P-123456"), position.id)
        self.assertEqual(1, len(position.events))
        self.assertTrue(position.is_long)
        self.assertFalse(position.is_short)
        self.assertTrue(position.is_open)
        self.assertFalse(position.is_closed)
        self.assertEqual(0, position.realized_points)
        self.assertEqual(0, position.realized_return)
        self.assertEqual(Money(-2.00, USD), position.realized_pnl)
        self.assertEqual(Money(49.00, USD), position.unrealized_pnl(last))
        self.assertEqual(Money(47.00, USD), position.total_pnl(last))
        self.assertEqual([Money(2.00, USD)], position.commissions())
        self.assertEqual("Position(LONG 100_000 AUD/USD.SIM, id=P-123456)",
                         repr(position))
Ejemplo n.º 22
0
 def cancel_order_command():
     return CancelOrder(
         trader_id=BetfairTestStubs.trader_id(),
         strategy_id=BetfairTestStubs.strategy_id(),
         instrument_id=BetfairTestStubs.instrument_id(),
         client_order_id=ClientOrderId("O-20210410-022422-001-001-1"),
         venue_order_id=VenueOrderId("229597791245"),
         command_id=BetfairTestStubs.uuid(),
         timestamp_ns=BetfairTestStubs.clock().timestamp_ns(),
     )
Ejemplo n.º 23
0
 def cancel_order_command():
     return CancelOrder(
         instrument_id=BetfairTestStubs.instrument_id(),
         trader_id=BetfairTestStubs.trader_id(),
         account_id=BetfairTestStubs.account_id(),
         client_order_id=ClientOrderId("1"),
         venue_order_id=VenueOrderId("1"),
         command_id=BetfairTestStubs.uuid(),
         timestamp_ns=BetfairTestStubs.clock().timestamp_ns(),
     )
    async def test_reconcile_state_when_order_completed_returns_true_with_warning2(
            self):
        # Arrange
        self.exec_engine.start()
        self.risk_engine.start()

        strategy = TradingStrategy()
        strategy.register(
            trader_id=self.trader_id,
            portfolio=self.portfolio,
            msgbus=self.msgbus,
            cache=self.cache,
            clock=self.clock,
            logger=self.logger,
        )

        order = strategy.order_factory.limit(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00000"),
        )

        submit_order = SubmitOrder(
            self.trader_id,
            strategy.id,
            None,
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        self.risk_engine.execute(submit_order)
        await asyncio.sleep(0)  # Process queue
        self.exec_engine.process(TestStubs.event_order_submitted(order))
        await asyncio.sleep(0)  # Process queue
        self.exec_engine.process(TestStubs.event_order_accepted(order))
        await asyncio.sleep(0)  # Process queue
        self.exec_engine.process(
            TestStubs.event_order_filled(order, AUDUSD_SIM))
        await asyncio.sleep(0)  # Process queue

        report = OrderStatusReport(
            client_order_id=order.client_order_id,
            venue_order_id=VenueOrderId("1"),  # <-- from stub event
            order_status=OrderStatus.FILLED,
            filled_qty=Quantity.from_int(100000),
            ts_init=0,
        )

        # Act
        result = await self.client.reconcile_state(report, order)

        # Assert
        assert result
Ejemplo n.º 25
0
    def test_cancel_order_when_already_pending_cancel_then_denies(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy()
        strategy.register(
            trader_id=self.trader_id,
            portfolio=self.portfolio,
            msgbus=self.msgbus,
            cache=self.cache,
            clock=self.clock,
            logger=self.logger,
        )

        order = strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        submit = SubmitOrder(
            self.trader_id,
            strategy.id,
            None,
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        cancel = CancelOrder(
            self.trader_id,
            strategy.id,
            order.instrument_id,
            order.client_order_id,
            VenueOrderId("1"),
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        self.risk_engine.execute(submit)
        self.exec_engine.process(TestStubs.event_order_submitted(order))
        self.exec_engine.process(TestStubs.event_order_accepted(order))

        self.risk_engine.execute(cancel)
        self.exec_engine.process(TestStubs.event_order_pending_cancel(order))

        # Act
        self.risk_engine.execute(cancel)

        # Assert
        assert self.exec_client.calls == [
            "_start", "submit_order", "cancel_order"
        ]
        assert self.risk_engine.command_count == 3
        assert self.exec_engine.command_count == 2
Ejemplo n.º 26
0
async def generate_order_status_report(self, order) -> Optional[OrderStatusReport]:
    return [
        OrderStatusReport(
            client_order_id=ClientOrderId(),
            venue_order_id=VenueOrderId(),
            order_state=OrderState(),
            filled_qty=Quantity.zero(),
            timestamp_ns=millis_to_nanos(),
        )
        for order in self.client().betting.list_current_orders()["currentOrders"]
    ]
Ejemplo n.º 27
0
    def test_modify_order_with_default_settings_then_sends_to_client(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy()
        strategy.register(
            trader_id=self.trader_id,
            portfolio=self.portfolio,
            msgbus=self.msgbus,
            cache=self.cache,
            clock=self.clock,
            logger=self.logger,
        )

        order = strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00010"),
        )

        submit = SubmitOrder(
            self.trader_id,
            strategy.id,
            None,
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        modify = ModifyOrder(
            self.trader_id,
            strategy.id,
            order.instrument_id,
            order.client_order_id,
            VenueOrderId("1"),
            order.quantity,
            Price.from_str("1.00010"),
            None,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        self.risk_engine.execute(submit)

        # Act
        self.risk_engine.execute(modify)

        # Assert
        assert self.exec_client.calls == [
            "_start", "submit_order", "modify_order"
        ]
        assert self.risk_engine.command_count == 2
        assert self.exec_engine.command_count == 2
Ejemplo n.º 28
0
    def event_order_filled(
        order,
        instrument,
        venue_order_id=None,
        execution_id=None,
        position_id=None,
        strategy_id=None,
        last_qty=None,
        last_px=None,
        liquidity_side=LiquiditySide.TAKER,
        execution_ns=0,
    ) -> OrderFilled:
        if venue_order_id is None:
            venue_order_id = VenueOrderId("1")
        if execution_id is None:
            execution_id = ExecutionId(
                order.client_order_id.value.replace("O", "E"))
        if position_id is None:
            position_id = order.position_id
        if strategy_id is None:
            strategy_id = order.strategy_id
        if last_px is None:
            last_px = Price("1.00000")
        if last_qty is None:
            last_qty = order.quantity

        commission = instrument.calculate_commission(
            last_qty=order.quantity,
            last_px=last_px,
            liquidity_side=liquidity_side,
        )

        return OrderFilled(
            account_id=TestStubs.account_id(),
            client_order_id=order.client_order_id,
            venue_order_id=venue_order_id,
            execution_id=execution_id,
            position_id=position_id,
            strategy_id=strategy_id,
            instrument_id=order.instrument_id,
            order_side=order.side,
            last_qty=last_qty,
            last_px=order.price if last_px is None else last_px,
            cum_qty=Quantity(order.filled_qty + last_qty),
            leaves_qty=Quantity(
                max(0, order.quantity - order.filled_qty - last_qty)),
            currency=instrument.quote_currency,
            is_inverse=instrument.is_inverse,
            commission=commission,
            liquidity_side=liquidity_side,
            execution_ns=execution_ns,
            event_id=uuid4(),
            timestamp_ns=0,
        )
Ejemplo n.º 29
0
 def event_order_accepted(order, venue_order_id=None) -> OrderAccepted:
     if venue_order_id is None:
         venue_order_id = VenueOrderId("1")
     return OrderAccepted(
         TestStubs.account_id(),
         order.client_order_id,
         venue_order_id,
         0,
         uuid4(),
         0,
     )
Ejemplo n.º 30
0
async def generate_order_status_report(self, order) -> Optional[OrderStatusReport]:
    return [
        OrderStatusReport(
            client_order_id=ClientOrderId(),
            venue_order_id=VenueOrderId(),
            order_status=OrderStatus(),
            filled_qty=Quantity.zero(),
            ts_init=int(pd.Timestamp(order["timestamp"]).to_datetime64()),
        )
        for order in self.client().betting.list_current_orders()["currentOrders"]
    ]