async def test_reconcile_state_no_cached_with_rejected_order(self):
        # Arrange
        report = OrderStatusReport(
            account_id=self.account_id,
            instrument_id=AUDUSD_SIM.id,
            client_order_id=ClientOrderId("O-123456"),
            venue_order_id=VenueOrderId("1"),
            order_side=OrderSide.BUY,
            order_type=OrderType.LIMIT,
            time_in_force=TimeInForce.GTC,
            order_status=OrderStatus.REJECTED,
            price=Price.from_str("1.00000"),
            quantity=Quantity.from_int(10_000),
            filled_qty=Quantity.from_int(0),
            post_only=True,
            cancel_reason="SOME_REASON",
            report_id=UUID4(),
            ts_accepted=0,
            ts_last=0,
            ts_init=0,
        )

        self.client.add_order_status_report(report)

        # Act
        result = await self.exec_engine.reconcile_state()

        # Assert
        assert result
        assert len(self.cache.orders()) == 1
        assert self.cache.orders()[0].status == OrderStatus.REJECTED
    async def test_reconcile_state_no_cached_with_partially_filled_order_and_no_trade(
            self):
        # Arrange
        venue_order_id = VenueOrderId("1")
        order_report = OrderStatusReport(
            account_id=self.account_id,
            instrument_id=AUDUSD_SIM.id,
            client_order_id=ClientOrderId("O-123456"),
            venue_order_id=venue_order_id,
            order_side=OrderSide.BUY,
            order_type=OrderType.LIMIT,
            time_in_force=TimeInForce.GTC,
            order_status=OrderStatus.PARTIALLY_FILLED,
            price=Price.from_str("1.00000"),
            quantity=Quantity.from_int(10_000),
            filled_qty=Quantity.from_int(5_000),
            avg_px=Decimal("1.00000"),
            post_only=True,
            report_id=UUID4(),
            ts_accepted=0,
            ts_triggered=0,
            ts_last=0,
            ts_init=0,
        )

        self.client.add_order_status_report(order_report)

        # Act
        result = await self.exec_engine.reconcile_state()

        # Assert
        assert result
        assert len(self.cache.orders()) == 1
        assert self.cache.orders()[0].status == OrderStatus.PARTIALLY_FILLED
    async def test_reconcile_state_no_cached_with_triggered_order(self):
        # Arrange
        report = OrderStatusReport(
            account_id=self.account_id,
            instrument_id=AUDUSD_SIM.id,
            client_order_id=ClientOrderId("O-123456"),
            venue_order_id=VenueOrderId("1"),
            order_side=OrderSide.BUY,
            order_type=OrderType.STOP_LIMIT,
            time_in_force=TimeInForce.GTC,
            order_status=OrderStatus.TRIGGERED,
            price=Price.from_str("0.99500"),
            trigger_price=Price.from_str("1.00000"),
            trigger_type=TriggerType.BID_ASK,
            offset_type=TrailingOffsetType.PRICE,
            quantity=Quantity.from_int(10_000),
            filled_qty=Quantity.from_int(0),
            post_only=True,
            report_id=UUID4(),
            ts_accepted=1_000_000_000,
            ts_triggered=2_000_000_000,
            ts_last=2_000_000_000,
            ts_init=3_000_000_000,
        )

        self.client.add_order_status_report(report)

        # Act
        result = await self.exec_engine.reconcile_state()

        # Assert
        assert result
        assert len(self.cache.orders()) == 1
        assert len(self.cache.orders_open()) == 1
        assert self.cache.orders()[0].status == OrderStatus.TRIGGERED
Ejemplo n.º 4
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.º 5
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)
    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.º 7
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"]
    ]
    async def test_reconcile_state_no_cached_with_filled_order_and_trade(self):
        # Arrange
        venue_order_id = VenueOrderId("1")
        order_report = OrderStatusReport(
            account_id=self.account_id,
            instrument_id=AUDUSD_SIM.id,
            client_order_id=ClientOrderId("O-123456"),
            venue_order_id=venue_order_id,
            order_side=OrderSide.BUY,
            order_type=OrderType.LIMIT,
            time_in_force=TimeInForce.GTC,
            order_status=OrderStatus.FILLED,
            price=Price.from_str("1.00000"),
            quantity=Quantity.from_int(10_000),
            filled_qty=Quantity.from_int(10_000),
            avg_px=Decimal("1.00000"),
            post_only=True,
            reduce_only=False,
            report_id=UUID4(),
            ts_accepted=0,
            ts_triggered=0,
            ts_last=0,
            ts_init=0,
        )

        trade_report = TradeReport(
            account_id=self.account_id,
            instrument_id=AUDUSD_SIM.id,
            client_order_id=ClientOrderId("O-123456"),
            venue_order_id=venue_order_id,
            trade_id=TradeId("1"),
            order_side=OrderSide.BUY,
            last_qty=Quantity.from_int(10_000),
            last_px=Price.from_str("1.00000"),
            commission=Money(0, USD),
            liquidity_side=LiquiditySide.MAKER,
            report_id=UUID4(),
            ts_event=0,
            ts_init=0,
        )

        self.client.add_order_status_report(order_report)
        self.client.add_trade_reports(venue_order_id, [trade_report])

        # Act
        result = await self.exec_engine.reconcile_state()

        # Assert
        assert result
        assert len(self.cache.orders()) == 1
        assert self.cache.orders()[0].status == OrderStatus.FILLED
Ejemplo n.º 9
0
def parse_trigger_order_status_http(
    account_id: AccountId,
    instrument: Instrument,
    triggers: Dict[int, VenueOrderId],
    data: Dict[str, Any],
    report_id: UUID4,
    ts_init: int,
) -> OrderStatusReport:
    order_id = data["id"]
    parent_order_id = triggers.get(order_id)  # Map trigger to parent
    client_id_str = data.get("clientId")
    trigger_price = data.get("triggerPrice")
    order_price = data.get("orderPrice")
    avg_px = data["avgFillPrice"]
    triggered_at = data["triggeredAt"]
    trail_value = data["trailValue"]
    created_at = int(
        pd.to_datetime(data["createdAt"], utc=True).to_datetime64())
    return OrderStatusReport(
        account_id=account_id,
        instrument_id=instrument.id,
        client_order_id=ClientOrderId(client_id_str)
        if client_id_str is not None else None,
        venue_order_id=parent_order_id or VenueOrderId(str(order_id)),
        order_side=OrderSide.BUY if data["side"] == "buy" else OrderSide.SELL,
        order_type=parse_order_type(data=data),
        time_in_force=TimeInForce.GTC,
        order_status=parse_order_status(data),
        price=instrument.make_price(order_price)
        if order_price is not None else None,
        trigger_price=instrument.make_price(trigger_price)
        if trigger_price is not None else None,
        trigger_type=TriggerType.LAST,
        trailing_offset=Decimal(str(trail_value))
        if trail_value is not None else None,
        offset_type=TrailingOffsetType.PRICE,
        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=False,
        reduce_only=data["reduceOnly"],
        report_id=report_id,
        ts_accepted=created_at,
        ts_triggered=int(
            pd.to_datetime(triggered_at, utc=True).to_datetime64())
        if triggered_at is not None else 0,
        ts_last=created_at,
        ts_init=ts_init,
    )
    def test_instantiate_order_status_report(self):
        # Arrange, Act
        report_id = UUID4()
        report = OrderStatusReport(
            account_id=AccountId("SIM", "001"),
            instrument_id=AUDUSD_IDEALPRO,
            client_order_id=ClientOrderId("O-123456"),
            order_list_id=OrderListId("1"),
            venue_order_id=VenueOrderId("2"),
            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_id,
            ts_accepted=1_000_000,
            ts_triggered=1_500_000,
            ts_last=2_000_000,
            ts_init=3_000_000,
        )

        # Assert
        assert (
            str(report)
            == f"OrderStatusReport(account_id=SIM-001, 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_id}, ts_accepted=1000000, ts_triggered=1500000, ts_last=2000000, ts_init=3000000)"  # noqa
        )
        assert (
            repr(report)
            == f"OrderStatusReport(account_id=SIM-001, 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_id}, ts_accepted=1000000, ts_triggered=1500000, ts_last=2000000, ts_init=3000000)"  # noqa
        )
Ejemplo n.º 11
0
    def test_handle_order_status_report(self):
        # Arrange
        order_report = OrderStatusReport(
            account_id=AccountId("SIM", "001"),
            instrument_id=AUDUSD_SIM.id,
            client_order_id=ClientOrderId("O-123456"),
            order_list_id=OrderListId("1"),
            venue_order_id=VenueOrderId("2"),
            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=UUID4(),
            ts_accepted=1_000_000,
            ts_triggered=1_500_000,
            ts_last=2_000_000,
            ts_init=3_000_000,
        )

        # Act
        self.exec_engine.reconcile_report(order_report)

        # Assert
        assert self.exec_engine.report_count == 1
Ejemplo n.º 12
0
def parse_order_report_http(
    account_id: AccountId,
    instrument_id: InstrumentId,
    data: BinanceFuturesOrder,
    report_id: UUID4,
    ts_init: int,
) -> OrderStatusReport:
    price = Decimal(data.price)
    trigger_price = Decimal(data.stopPrice)
    avg_px = Decimal(data.avgPrice)
    time_in_force = BinanceFuturesTimeInForce(data.timeInForce.upper())
    return OrderStatusReport(
        account_id=account_id,
        instrument_id=instrument_id,
        client_order_id=ClientOrderId(data.clientOrderId)
        if data.clientOrderId != "" else None,
        venue_order_id=VenueOrderId(str(data.orderId)),
        order_side=OrderSide[data.side.upper()],
        order_type=parse_order_type(data.type),
        time_in_force=parse_time_in_force(time_in_force),
        order_status=parse_order_status(data.status),
        price=Price.from_str(data.price) if price is not None else None,
        quantity=Quantity.from_str(data.origQty),
        filled_qty=Quantity.from_str(data.executedQty),
        avg_px=avg_px if avg_px > 0 else None,
        post_only=time_in_force == BinanceFuturesTimeInForce.GTX,
        reduce_only=data.reduceOnly,
        report_id=report_id,
        ts_accepted=millis_to_nanos(data.time),
        ts_last=millis_to_nanos(data.updateTime),
        ts_init=ts_init,
        trigger_price=Price.from_str(str(trigger_price))
        if trigger_price > 0 else None,
        trigger_type=parse_trigger_type(data.workingType),
        trailing_offset=Decimal(data.priceRate) *
        100 if data.priceRate is not None else None,
        offset_type=TrailingOffsetType.BASIS_POINTS
        if data.priceRate is not None else TrailingOffsetType.NONE,
    )
Ejemplo n.º 13
0
    def _generate_external_order_status(
        self,
        instrument_id: InstrumentId,
        client_order_id: ClientOrderId,
        venue_order_id: VenueOrderId,
        data: BinanceFuturesOrderData,
        ts_event: int,
    ) -> None:
        report = OrderStatusReport(
            account_id=self.account_id,
            instrument_id=instrument_id,
            client_order_id=client_order_id,
            venue_order_id=venue_order_id,
            order_side=OrderSide.BUY
            if data.S == BinanceOrderSide.BUY else OrderSide.SELL,
            order_type=parse_order_type(data.o),
            time_in_force=parse_time_in_force(data.f),
            order_status=OrderStatus.ACCEPTED,
            price=Price.from_str(data.p) if data.p is not None else None,
            trigger_price=Price.from_str(data.sp)
            if data.sp is not None else None,
            trigger_type=parse_trigger_type(data.wt),
            trailing_offset=Decimal(data.cr) *
            100 if data.cr is not None else None,
            offset_type=TrailingOffsetType.BASIS_POINTS,
            quantity=Quantity.from_str(data.q),
            filled_qty=Quantity.from_str(data.z),
            avg_px=None,
            post_only=data.f == BinanceFuturesTimeInForce.GTX,
            reduce_only=data.R,
            report_id=self._uuid_factory.generate(),
            ts_accepted=ts_event,
            ts_last=ts_event,
            ts_init=self._clock.timestamp_ns(),
        )

        self._send_order_status_report(report)
Ejemplo n.º 14
0
def parse_order_report_http(
    account_id: AccountId,
    instrument_id: InstrumentId,
    data: Dict[str, Any],
    report_id: UUID4,
    ts_init: int,
) -> OrderStatusReport:
    client_id_str = data.get("clientOrderId")
    order_type = data["type"].upper()
    price = data.get("price")
    trigger_price = Decimal(data["stopPrice"])
    avg_px = Decimal(data["price"])
    return OrderStatusReport(
        account_id=account_id,
        instrument_id=instrument_id,
        client_order_id=ClientOrderId(client_id_str)
        if client_id_str is not None else None,
        venue_order_id=VenueOrderId(str(data["orderId"])),
        order_side=OrderSide[data["side"].upper()],
        order_type=parse_order_type(order_type),
        time_in_force=parse_time_in_force(data["timeInForce"].upper()),
        order_status=TimeInForce(data["status"].upper()),
        price=Price.from_str(price) if price is not None else None,
        quantity=Quantity.from_str(data["origQty"]),
        filled_qty=Quantity.from_str(data["executedQty"]),
        avg_px=avg_px if avg_px > 0 else None,
        post_only=order_type == "LIMIT_MAKER",
        reduce_only=False,
        report_id=report_id,
        ts_accepted=millis_to_nanos(data["time"]),
        ts_last=millis_to_nanos(data["updateTime"]),
        ts_init=ts_init,
        trigger_price=Price.from_str(str(trigger_price))
        if trigger_price > 0 else None,
        trigger_type=TriggerType.LAST
        if trigger_price > 0 else TriggerType.NONE,
    )