def test_process(self):
        # Arrange
        ethusdt = TestInstrumentProvider.ethusdt_binance()
        wrangler = TradeTickDataWrangler(instrument=ethusdt)
        provider = TestDataProvider()

        # Act
        ticks = wrangler.process(
            provider.read_csv_ticks("binance-ethusdt-trades.csv")[:100])

        # Assert
        assert len(ticks) == 100
        assert ticks[0].price == Price.from_str("423.760")
        assert ticks[0].size == Quantity.from_str("2.67900")
        assert ticks[0].aggressor_side == AggressorSide.SELL
        assert ticks[0].trade_id == "148568980"
        assert ticks[0].ts_event == 1597399200223000064
        assert ticks[0].ts_init == 1597399200223000064
Exemplo n.º 2
0
    def test_build_ticks(self):
        # Arrange
        tick_data = TestDataProvider.tardis_trades()
        self.tick_builder = TradeTickDataWrangler(
            instrument=TestInstrumentProvider.btcusdt_binance(),
            data=tick_data,
        )

        # Act
        self.tick_builder.pre_process(0)
        ticks = self.tick_builder.build_ticks()

        # Assert
        self.assertEqual(9999, len(ticks))
        self.assertEqual(Price.from_str("9682.00"), ticks[0].price)
        self.assertEqual(Quantity.from_str("0.132000"), ticks[0].size)
        self.assertEqual(AggressorSide.BUY, ticks[0].aggressor_side)
        self.assertEqual("42377944", ticks[0].match_id)
        self.assertEqual(1582329602418379008, ticks[0].ts_recv_ns)
Exemplo n.º 3
0
    def test_update_order(self):
        # Arrange
        instrument = IBTestStubs.instrument("AAPL")
        contract_details = IBTestStubs.contract_details("AAPL")
        contract = contract_details.contract
        order = IBTestStubs.create_order()
        self.instrument_setup(instrument=instrument,
                              contract_details=contract_details)
        self.exec_client._ib_insync_orders[
            TestIdStubs.client_order_id()] = Trade(contract=contract,
                                                   order=order)

        # Act
        command = TestCommandStubs.modify_order_command(
            instrument_id=instrument.id,
            price=Price.from_int(10),
            quantity=Quantity.from_str("100"),
        )
        with patch.object(self.exec_client._client, "placeOrder") as mock:
            self.exec_client.modify_order(command=command)

        # Assert
        expected = {
            "contract":
            Contract(
                secType="STK",
                conId=265598,
                symbol="AAPL",
                exchange="SMART",
                primaryExchange="NASDAQ",
                currency="USD",
                localSymbol="AAPL",
                tradingClass="NMS",
            ),
            "order":
            LimitOrder(action="BUY", totalQuantity=100, lmtPrice=10.0),
        }
        name, args, kwargs = mock.mock_calls[0]
        # Can't directly compare kwargs for some reason?
        assert kwargs["contract"] == expected["contract"]
        assert kwargs["order"].action == expected["order"].action
        assert kwargs["order"].totalQuantity == expected["order"].totalQuantity
        assert kwargs["order"].lmtPrice == expected["order"].lmtPrice
Exemplo n.º 4
0
    def test_build_ticks(self):
        # Arrange
        tick_data = TestDataProvider.ethusdt_trades()
        self.tick_builder = TradeTickDataWrangler(
            instrument=TestInstrumentProvider.ethusdt_binance(),
            data=tick_data,
        )

        # Act
        self.tick_builder.pre_process(0)
        ticks = self.tick_builder.build_ticks()

        # Assert
        self.assertEqual(69806, len(ticks))
        self.assertEqual(Price.from_str("423.760"), ticks[0].price)
        self.assertEqual(Quantity.from_str("2.67900"), ticks[0].size)
        self.assertEqual(AggressorSide.SELL, ticks[0].aggressor_side)
        self.assertEqual("148568980", ticks[0].match_id)
        self.assertEqual(1597399200223000064, ticks[0].ts_recv_ns)
    def test_execute_command(self):
        order = self.strategy.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity.from_str("1.00000000"),
        )

        command = SubmitOrder(
            self.trader_id,
            self.strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        def execute_command():
            self.exec_engine.execute(command)

        self.benchmark.pedantic(execute_command, iterations=10_000, rounds=1)
Exemplo n.º 6
0
 def _on_trade_ticker_update(self, ticker: Ticker):
     instrument_id = self._instrument_provider.contract_id_to_instrument_id[
         ticker.contract.conId]
     for tick in ticker.ticks:
         price = str(tick.price)
         size = str(tick.size)
         ts_event = dt_to_unix_nanos(tick.time)
         update = TradeTick(
             instrument_id=instrument_id,
             price=Price.from_str(price),
             size=Quantity.from_str(size),
             aggressor_side=AggressorSide.UNKNOWN,
             trade_id=generate_trade_id(symbol=instrument_id.value,
                                        ts_event=ts_event,
                                        price=price,
                                        size=size),
             ts_event=ts_event,
             ts_init=self._clock.timestamp_ns(),
         )
         self._handle_data(update)
Exemplo n.º 7
0
def parse_historic_trade_ticks(historic_ticks: List[HistoricalTickLast],
                               instrument_id: InstrumentId) -> List[TradeTick]:
    trades = []
    for tick in historic_ticks:
        ts_init = dt_to_unix_nanos(tick.time)
        trade_tick = TradeTick(
            instrument_id=instrument_id,
            price=Price.from_str(str(tick.price)),
            size=Quantity.from_str(str(tick.size)),
            aggressor_side=AggressorSide.UNKNOWN,
            trade_id=generate_trade_id(
                symbol=instrument_id.symbol.value,
                ts_event=ts_init,
                price=tick.price,
                size=tick.size,
            ),
            ts_init=ts_init,
            ts_event=ts_init,
        )
        trades.append(trade_tick)

    return trades
Exemplo n.º 8
0
    def test_aggressive_partial_fill(self):
        # Arrange: Prepare market
        self.cache.add_instrument(USDJPY_SIM)

        quote = QuoteTick(
            instrument_id=USDJPY_SIM.id,
            bid=Price.from_str("110.000"),
            ask=Price.from_str("110.010"),
            bid_size=Quantity.from_int(1500000),
            ask_size=Quantity.from_int(1500000),
            ts_event=0,
            ts_init=0,
        )
        self.data_engine.process(quote)
        snapshot = TestDataStubs.order_book_snapshot(
            instrument_id=USDJPY_SIM.id,
            bid_volume=1000,
            ask_volume=1000,
        )
        self.data_engine.process(snapshot)
        self.exchange.process_order_book(snapshot)

        # Act
        order = self.strategy.order_factory.limit(
            instrument_id=USDJPY_SIM.id,
            order_side=OrderSide.BUY,
            quantity=Quantity.from_int(7000),
            price=Price.from_int(20),
            post_only=False,
        )
        self.strategy.submit_order(order)
        self.exchange.process(0)

        # Assert
        assert order.status == OrderStatus.PARTIALLY_FILLED
        assert order.filled_qty == Quantity.from_str("6000.0")  # No slippage
        assert order.avg_px == Decimal("15.93333333333333333333333333")
        assert self.exchange.get_account().balance_total(USD) == Money(
            999999.88, USD)
Exemplo n.º 9
0
def parse_trade_report_http(
    account_id: AccountId,
    instrument_id: InstrumentId,
    data: Dict[str, Any],
    report_id: UUID4,
    ts_init: int,
) -> TradeReport:
    return TradeReport(
        account_id=account_id,
        instrument_id=instrument_id,
        venue_order_id=VenueOrderId(str(data["orderId"])),
        trade_id=TradeId(str(data["id"])),
        order_side=OrderSide.BUY if data["isBuyer"] else OrderSide.SELL,
        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["isMaker"] else LiquiditySide.TAKER,
        report_id=report_id,
        ts_event=millis_to_nanos(data["time"]),
        ts_init=ts_init,
    )
Exemplo n.º 10
0
    def test_order_filled(self):
        # Arrange
        uuid = uuid4()
        event = OrderFilled(
            account_id=AccountId("SIM", "000"),
            client_order_id=ClientOrderId("O-2020872378423"),
            venue_order_id=VenueOrderId("123456"),
            execution_id=ExecutionId("1"),
            position_id=PositionId("2"),
            strategy_id=StrategyId("SCALPER-001"),
            instrument_id=InstrumentId(Symbol("BTC/USDT"), Venue("BINANCE")),
            order_side=OrderSide.BUY,
            last_qty=Quantity.from_str("0.561000"),
            last_px=Price.from_str("15600.12445"),
            currency=USDT,
            commission=Money(12.20000000, USDT),
            liquidity_side=LiquiditySide.MAKER,
            execution_ns=0,
            event_id=uuid,
            timestamp_ns=0,
        )

        print(event)
        # Act
        assert (
            f"OrderFilled(account_id=SIM-000, client_order_id=O-2020872378423, "
            f"venue_order_id=123456, position_id=2, strategy_id=SCALPER-001, "
            f"instrument_id=BTC/USDT.BINANCE, side=BUY-MAKER, last_qty=0.561000, "
            f"last_px=15600.12445, "
            f"commission=12.20000000 USDT, event_id={uuid})" == str(event))
        assert (
            f"OrderFilled(account_id=SIM-000, client_order_id=O-2020872378423, "
            f"venue_order_id=123456, position_id=2, strategy_id=SCALPER-001, "
            f"instrument_id=BTC/USDT.BINANCE, side=BUY-MAKER, last_qty=0.561000, "
            f"last_px=15600.12445, "
            f"commission=12.20000000 USDT, event_id={uuid})" == repr(event))
Exemplo n.º 11
0
    def test_order_initialized(self):
        # Arrange
        uuid = uuid4()
        event = OrderInitialized(
            client_order_id=ClientOrderId("O-2020872378423"),
            strategy_id=StrategyId("SCALPER-001"),
            instrument_id=InstrumentId(Symbol("BTC/USDT"), Venue("BINANCE")),
            order_side=OrderSide.BUY,
            order_type=OrderType.LIMIT,
            quantity=Quantity.from_str("0.561000"),
            time_in_force=TimeInForce.DAY,
            event_id=uuid,
            timestamp_ns=0,
            options={"Price": "15200.10"},
        )

        # Act
        # Assert
        assert (
            f"OrderInitialized(client_order_id=O-2020872378423, strategy_id=SCALPER-001, event_id={uuid})"
            == str(event))
        assert (
            f"OrderInitialized(client_order_id=O-2020872378423, strategy_id=SCALPER-001, event_id={uuid})"
            == repr(event))
Exemplo n.º 12
0
    def test_calculate_unrealized_pnl_for_short(self):
        # Arrange
        order = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.SELL,
            Quantity.from_str("5.912000"),
        )

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

        position = Position(instrument=BTCUSDT_BINANCE, fill=fill)

        pnl = position.unrealized_pnl(Price.from_str("10407.15"))

        # Assert
        self.assertEqual(Money(582.03640000, USDT), pnl)
        self.assertEqual(Money(-62.10910720, USDT), position.realized_pnl)
        self.assertEqual([Money(62.10910720, USDT)], position.commissions())
Exemplo n.º 13
0
    def test_order_filled_event_to_from_dict_and_str_repr(self):
        # Arrange
        uuid = UUID4()
        event = OrderFilled(
            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"),
            execution_id=ExecutionId("1"),
            position_id=PositionId("2"),
            order_side=OrderSide.BUY,
            order_type=OrderType.LIMIT,
            last_qty=Quantity.from_str("0.561000"),
            last_px=Price.from_str("15600.12445"),
            currency=USDT,
            commission=Money(12.20000000, USDT),
            liquidity_side=LiquiditySide.MAKER,
            ts_event=0,
            event_id=uuid,
            ts_init=0,
        )

        # Act, Assert
        assert event.is_buy
        assert not event.is_sell
        assert OrderFilled.from_dict(OrderFilled.to_dict(event)) == event
        assert (
            str(event) ==
            "OrderFilled(account_id=SIM-000, instrument_id=BTC/USDT.BINANCE, client_order_id=O-2020872378423, venue_order_id=123456, execution_id=1, position_id=2, order_side=BUY, order_type=LIMIT, last_qty=0.561000, last_px=15600.12445 USDT, commission=12.20000000 USDT, liquidity_side=MAKER, ts_event=0)"  # noqa
        )
        assert (
            repr(event) ==
            f"OrderFilled(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, execution_id=1, position_id=2, order_side=BUY, order_type=LIMIT, last_qty=0.561000, last_px=15600.12445 USDT, commission=12.20000000 USDT, liquidity_side=MAKER, event_id={uuid}, ts_event=0, ts_init=0)"  # noqa
        )
Exemplo n.º 14
0
    def test_opening_positions_with_multi_asset_account(self):
        # Arrange
        state = AccountState(
            account_id=AccountId("BITMEX", "01234"),
            account_type=AccountType.CASH,
            base_currency=None,  # Multi-currency account
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    ETH,
                    Money(20.00000000, ETH),
                    Money(0.00000000, ETH),
                    Money(20.00000000, ETH),
                ),
            ],
            info={},
            event_id=uuid4(),
            updated_ns=0,
            timestamp_ns=0,
        )

        self.exec_engine.process(state)

        last_ethusd = QuoteTick(
            ETHUSD_BITMEX.id,
            Price.from_str("376.05"),
            Price.from_str("377.10"),
            Quantity.from_str("16"),
            Quantity.from_str("25"),
            0,
            0,
        )

        last_btcusd = QuoteTick(
            BTCUSD_BITMEX.id,
            Price.from_str("10500.05"),
            Price.from_str("10501.51"),
            Quantity.from_str("2.54"),
            Quantity.from_str("0.91"),
            0,
            0,
        )

        self.cache.add_quote_tick(last_ethusd)
        self.cache.add_quote_tick(last_btcusd)
        self.portfolio.update_tick(last_ethusd)
        self.portfolio.update_tick(last_btcusd)

        order = self.order_factory.market(
            ETHUSD_BITMEX.id,
            OrderSide.BUY,
            Quantity.from_int(10000),
        )

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

        position = Position(instrument=ETHUSD_BITMEX, fill=fill)

        # Act
        self.cache.add_position(position)
        self.portfolio.update_position(
            TestStubs.event_position_opened(position))

        # Assert
        self.assertEqual(
            {ETH: Money(26.59220848, ETH)},
            self.portfolio.net_exposures(BITMEX),
        )
        self.assertEqual(
            {ETH: Money(0.20608962, ETH)},
            self.portfolio.maint_margins(BITMEX),
        )
        self.assertEqual(
            Money(26.59220848, ETH),
            self.portfolio.net_exposure(ETHUSD_BITMEX.id),
        )
        self.assertEqual(
            Money(0.00000000, ETH),
            self.portfolio.unrealized_pnl(ETHUSD_BITMEX.id),
        )
Exemplo n.º 15
0
    def test_opening_one_short_position_updates_portfolio(self):
        # Arrange
        state = AccountState(
            account_id=AccountId("BINANCE", "01234"),
            account_type=AccountType.CASH,
            base_currency=None,  # Multi-currency account
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    ETH,
                    Money(20.00000000, ETH),
                    Money(0.00000000, ETH),
                    Money(20.00000000, ETH),
                ),
            ],
            info={},
            event_id=uuid4(),
            updated_ns=0,
            timestamp_ns=0,
        )

        self.exec_engine.process(state)

        order = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.SELL,
            Quantity.from_str("0.515"),
        )

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

        last = QuoteTick(
            BTCUSDT_BINANCE.id,
            Price.from_str("15510.15"),
            Price.from_str("15510.25"),
            Quantity.from_str("12.62"),
            Quantity.from_str("3.1"),
            0,
            0,
        )

        self.cache.add_quote_tick(last)
        self.portfolio.update_tick(last)

        position = Position(instrument=BTCUSDT_BINANCE, fill=fill)

        # Act
        self.cache.add_position(position)
        self.portfolio.update_position(
            TestStubs.event_position_opened(position))

        # Assert
        self.assertEqual(
            {USDT: Money(7987.77875000, USDT)},
            self.portfolio.net_exposures(BINANCE),
        )
        self.assertEqual(
            {USDT: Money(-262.77875000, USDT)},
            self.portfolio.unrealized_pnls(BINANCE),
        )
        self.assertEqual(
            {USDT: Money(7.98777875, USDT)},
            self.portfolio.maint_margins(BINANCE),
        )
        self.assertEqual(
            Money(7987.77875000, USDT),
            self.portfolio.net_exposure(BTCUSDT_BINANCE.id),
        )
        self.assertEqual(
            Money(-262.77875000, USDT),
            self.portfolio.unrealized_pnl(BTCUSDT_BINANCE.id),
        )
        self.assertEqual(
            Decimal("-0.515"),
            self.portfolio.net_position(order.instrument_id),
        )
        self.assertFalse(self.portfolio.is_net_long(order.instrument_id))
        self.assertTrue(self.portfolio.is_net_short(order.instrument_id))
        self.assertFalse(self.portfolio.is_flat(order.instrument_id))
        self.assertFalse(self.portfolio.is_completely_flat())
Exemplo n.º 16
0
    def test_handle_quote_tick_when_value_beyond_threshold_sends_bar_to_handler(
            self):
        # Arrange
        bar_store = ObjectStorer()
        handler = bar_store.store
        instrument_id = TestStubs.audusd_id()
        bar_spec = BarSpecification(100000, BarAggregation.VALUE,
                                    PriceType.BID)
        bar_type = BarType(instrument_id, bar_spec)
        aggregator = ValueBarAggregator(
            AUDUSD_SIM,
            bar_type,
            handler,
            Logger(TestClock()),
        )

        tick1 = QuoteTick(
            instrument_id=AUDUSD_SIM.id,
            bid=Price.from_str("1.00001"),
            ask=Price.from_str("1.00004"),
            bid_size=Quantity.from_int(20000),
            ask_size=Quantity.from_int(20000),
            ts_event_ns=0,
            ts_recv_ns=0,
        )

        tick2 = QuoteTick(
            instrument_id=AUDUSD_SIM.id,
            bid=Price.from_str("1.00002"),
            ask=Price.from_str("1.00005"),
            bid_size=Quantity.from_int(60000),
            ask_size=Quantity.from_int(20000),
            ts_event_ns=0,
            ts_recv_ns=0,
        )

        tick3 = QuoteTick(
            instrument_id=AUDUSD_SIM.id,
            bid=Price.from_str("1.00000"),
            ask=Price.from_str("1.00003"),
            bid_size=Quantity.from_int(30500),
            ask_size=Quantity.from_int(20000),
            ts_event_ns=0,
            ts_recv_ns=0,
        )

        # Act
        aggregator.handle_quote_tick(tick1)
        aggregator.handle_quote_tick(tick2)
        aggregator.handle_quote_tick(tick3)

        # Assert
        self.assertEqual(1, len(bar_store.get_store()))
        self.assertEqual(Price.from_str("1.00001"),
                         bar_store.get_store()[0].open)
        self.assertEqual(Price.from_str("1.00002"),
                         bar_store.get_store()[0].high)
        self.assertEqual(Price.from_str("1.00000"),
                         bar_store.get_store()[0].low)
        self.assertEqual(Price.from_str("1.00000"),
                         bar_store.get_store()[0].close)
        self.assertEqual(Quantity.from_str("99999"),
                         bar_store.get_store()[0].volume)
        self.assertEqual(Decimal("10501.400"),
                         aggregator.get_cumulative_value())
Exemplo n.º 17
0
    def test_opening_one_short_position_updates_portfolio(self):
        # Arrange
        AccountFactory.register_calculated_account("BINANCE")

        account_id = AccountId("BINANCE", "01234")
        state = AccountState(
            account_id=account_id,
            account_type=AccountType.MARGIN,
            base_currency=None,  # Multi-currency account
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    ETH,
                    Money(20.00000000, ETH),
                    Money(0.00000000, ETH),
                    Money(20.00000000, ETH),
                ),
                AccountBalance(
                    USDT,
                    Money(100000.00000000, USDT),
                    Money(0.00000000, USDT),
                    Money(100000.00000000, USDT),
                ),
            ],
            info={},
            event_id=UUID4(),
            ts_event=0,
            ts_init=0,
        )

        self.portfolio.update_account(state)

        order = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.SELL,
            Quantity.from_str("0.515"),
        )

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

        last = QuoteTick(
            instrument_id=BTCUSDT_BINANCE.id,
            bid=Price.from_str("15510.15"),
            ask=Price.from_str("15510.25"),
            bid_size=Quantity.from_str("12.62"),
            ask_size=Quantity.from_str("3.1"),
            ts_event=0,
            ts_init=0,
        )

        self.cache.add_quote_tick(last)
        self.portfolio.update_tick(last)

        position = Position(instrument=BTCUSDT_BINANCE, fill=fill)

        # Act
        self.cache.add_position(position, OMSType.HEDGING)
        self.portfolio.update_position(
            TestStubs.event_position_opened(position))

        # Assert
        assert self.portfolio.net_exposures(BINANCE) == {
            USDT: Money(7987.77875000, USDT)
        }
        assert self.portfolio.unrealized_pnls(BINANCE) == {
            USDT: Money(-262.77875000, USDT)
        }
        assert self.portfolio.margins_maint(BINANCE) == {
            BTCUSDT_BINANCE.id: Money(7.72500000, USDT)
        }
        assert self.portfolio.net_exposure(BTCUSDT_BINANCE.id) == Money(
            7987.77875000, USDT)
        assert self.portfolio.unrealized_pnl(BTCUSDT_BINANCE.id) == Money(
            -262.77875000, USDT)
        assert self.portfolio.net_position(
            order.instrument_id) == Decimal("-0.515")
        assert not self.portfolio.is_net_long(order.instrument_id)
        assert self.portfolio.is_net_short(order.instrument_id)
        assert not self.portfolio.is_flat(order.instrument_id)
        assert not self.portfolio.is_completely_flat()
Exemplo n.º 18
0
    def test_market_value_when_insufficient_data_for_xrate_returns_none(self):
        # Arrange
        state = AccountState(
            account_id=AccountId("BITMEX", "01234"),
            account_type=AccountType.MARGIN,
            base_currency=BTC,
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
            ],
            info={},
            event_id=uuid4(),
            updated_ns=0,
            timestamp_ns=0,
        )

        self.exec_engine.process(state)

        order = self.order_factory.market(
            ETHUSD_BITMEX.id,
            OrderSide.BUY,
            Quantity.from_int(100),
        )

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

        last_ethusd = QuoteTick(
            ETHUSD_BITMEX.id,
            Price.from_str("376.05"),
            Price.from_str("377.10"),
            Quantity.from_str("16"),
            Quantity.from_str("25"),
            0,
            0,
        )

        last_xbtusd = QuoteTick(
            BTCUSD_BITMEX.id,
            Price.from_str("50000.00"),
            Price.from_str("50000.00"),
            Quantity.from_str("1"),
            Quantity.from_str("1"),
            0,
            0,
        )

        position = Position(instrument=ETHUSD_BITMEX, fill=fill)

        self.portfolio.update_position(
            TestStubs.event_position_opened(position))
        self.cache.add_position(position)
        self.cache.add_quote_tick(last_ethusd)
        self.cache.add_quote_tick(last_xbtusd)
        self.portfolio.update_tick(last_ethusd)
        self.portfolio.update_tick(last_xbtusd)

        # Act
        result = self.portfolio.net_exposures(BITMEX)

        # Assert
        self.assertEqual({BTC: Money(0.00200000, BTC)}, result)
Exemplo n.º 19
0
def parse_perpetual_instrument_http(
    symbol_info: BinanceFuturesSymbolInfo,
    ts_event: int,
    ts_init: int,
) -> CryptoPerpetual:
    # Create base asset
    base_currency = Currency(
        code=symbol_info.baseAsset,
        precision=symbol_info.baseAssetPrecision,
        iso4217=0,  # Currently undetermined for crypto assets
        name=symbol_info.baseAsset,
        currency_type=CurrencyType.CRYPTO,
    )

    # Create quote asset
    quote_currency = Currency(
        code=symbol_info.quoteAsset,
        precision=symbol_info.quotePrecision,
        iso4217=0,  # Currently undetermined for crypto assets
        name=symbol_info.quoteAsset,
        currency_type=CurrencyType.CRYPTO,
    )

    symbol = Symbol(symbol_info.symbol + "-PERP")
    instrument_id = InstrumentId(symbol=symbol, venue=BINANCE_VENUE)

    # Parse instrument filters
    filters: Dict[BinanceSymbolFilterType, BinanceSymbolFilter] = {
        f.filterType: f
        for f in symbol_info.filters
    }
    price_filter: BinanceSymbolFilter = filters.get(
        BinanceSymbolFilterType.PRICE_FILTER)
    lot_size_filter: BinanceSymbolFilter = filters.get(
        BinanceSymbolFilterType.LOT_SIZE)
    min_notional_filter: BinanceSymbolFilter = filters.get(
        BinanceSymbolFilterType.MIN_NOTIONAL)

    tick_size = price_filter.tickSize.rstrip("0")
    step_size = lot_size_filter.stepSize.rstrip("0")
    price_precision = precision_from_str(tick_size)
    size_precision = precision_from_str(step_size)
    price_increment = Price.from_str(tick_size)
    size_increment = Quantity.from_str(step_size)
    max_quantity = Quantity(float(lot_size_filter.maxQty),
                            precision=size_precision)
    min_quantity = Quantity(float(lot_size_filter.minQty),
                            precision=size_precision)
    min_notional = None
    if filters.get(BinanceSymbolFilterType.MIN_NOTIONAL):
        min_notional = Money(min_notional_filter.minNotional,
                             currency=quote_currency)
    max_price = Price(float(price_filter.maxPrice), precision=price_precision)
    min_price = Price(float(price_filter.minPrice), precision=price_precision)

    # Futures commissions
    maker_fee = Decimal("0.0002")  # TODO
    taker_fee = Decimal("0.0004")  # TODO

    assert symbol_info.marginAsset == symbol_info.quoteAsset

    # Create instrument
    return CryptoPerpetual(
        instrument_id=instrument_id,
        native_symbol=Symbol(symbol_info.symbol),
        base_currency=base_currency,
        quote_currency=quote_currency,
        settlement_currency=quote_currency,
        is_inverse=False,  # No inverse instruments trade on Binance
        price_precision=price_precision,
        size_precision=size_precision,
        price_increment=price_increment,
        size_increment=size_increment,
        max_quantity=max_quantity,
        min_quantity=min_quantity,
        max_notional=None,
        min_notional=min_notional,
        max_price=max_price,
        min_price=min_price,
        margin_init=Decimal(0),
        margin_maint=Decimal(0),
        maker_fee=maker_fee,
        taker_fee=taker_fee,
        ts_event=ts_event,
        ts_init=ts_init,
        info=orjson.loads(msgspec.json.encode(symbol_info)),
    )
def test_simulate_order_fills_single(asks):
    fills = asks.simulate_order_fills(
        order=Order(price=15, size=10, side=OrderSide.BUY, id="1"))
    assert fills == [(Price.from_str("15.0000"), Quantity.from_str("10.0000"))]
Exemplo n.º 21
0
    def test_opening_positions_with_multi_asset_account(self):
        # Arrange
        AccountFactory.register_calculated_account("BITMEX")

        account_id = AccountId("BITMEX", "01234")
        state = AccountState(
            account_id=account_id,
            account_type=AccountType.MARGIN,
            base_currency=None,  # Multi-currency account
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    ETH,
                    Money(20.00000000, ETH),
                    Money(0.00000000, ETH),
                    Money(20.00000000, ETH),
                ),
            ],
            info={},
            event_id=UUID4(),
            ts_event=0,
            ts_init=0,
        )

        self.portfolio.update_account(state)

        last_ethusd = QuoteTick(
            instrument_id=ETHUSD_BITMEX.id,
            bid=Price.from_str("376.05"),
            ask=Price.from_str("377.10"),
            bid_size=Quantity.from_str("16"),
            ask_size=Quantity.from_str("25"),
            ts_event=0,
            ts_init=0,
        )

        last_btcusd = QuoteTick(
            instrument_id=BTCUSD_BITMEX.id,
            bid=Price.from_str("10500.05"),
            ask=Price.from_str("10501.51"),
            bid_size=Quantity.from_str("2.54"),
            ask_size=Quantity.from_str("0.91"),
            ts_event=0,
            ts_init=0,
        )

        self.cache.add_quote_tick(last_ethusd)
        self.cache.add_quote_tick(last_btcusd)
        self.portfolio.update_tick(last_ethusd)
        self.portfolio.update_tick(last_btcusd)

        order = self.order_factory.market(
            ETHUSD_BITMEX.id,
            OrderSide.BUY,
            Quantity.from_int(10000),
        )

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

        position = Position(instrument=ETHUSD_BITMEX, fill=fill)

        # Act
        self.cache.add_position(position, OMSType.HEDGING)
        self.portfolio.update_position(
            TestStubs.event_position_opened(position))

        # Assert
        assert self.portfolio.net_exposures(BITMEX) == {
            ETH: Money(26.59220848, ETH)
        }
        assert self.portfolio.margins_maint(BITMEX) == {
            ETHUSD_BITMEX.id: Money(0.20608962, ETH)
        }
        assert self.portfolio.net_exposure(ETHUSD_BITMEX.id) == Money(
            26.59220848, ETH)
        assert self.portfolio.unrealized_pnl(ETHUSD_BITMEX.id) == Money(
            0.00000000, ETH)
Exemplo n.º 22
0
    def _handle_execution_report(self, data: Dict[str, Any]):
        execution_type: str = data["x"]

        instrument_id: InstrumentId = self._get_cached_instrument_id(data["s"])

        # Parse client order ID
        client_order_id_str: str = data["c"]
        if not client_order_id_str or not client_order_id_str.startswith("O"):
            client_order_id_str = data["C"]
        client_order_id = ClientOrderId(client_order_id_str)

        # Fetch strategy ID
        strategy_id: StrategyId = self._cache.strategy_id_for_order(client_order_id)
        if strategy_id is None:
            # TODO(cs): Implement external order handling
            self._log.error(
                f"Cannot handle trade report: strategy ID for {client_order_id} not found.",
            )
            return

        venue_order_id = VenueOrderId(str(data["i"]))
        ts_event: int = millis_to_nanos(data["E"])

        if execution_type == "NEW":
            self.generate_order_accepted(
                strategy_id=strategy_id,
                instrument_id=instrument_id,
                client_order_id=client_order_id,
                venue_order_id=venue_order_id,
                ts_event=ts_event,
            )
        elif execution_type in "TRADE":
            instrument: Instrument = self._instrument_provider.find(instrument_id=instrument_id)

            # Determine commission
            commission_asset: str = data["N"]
            commission_amount: str = data["n"]
            if commission_asset is not None:
                commission = Money.from_str(f"{commission_amount} {commission_asset}")
            else:
                # Binance typically charges commission as base asset or BNB
                commission = Money(0, instrument.base_currency)

            self.generate_order_filled(
                strategy_id=strategy_id,
                instrument_id=instrument_id,
                client_order_id=client_order_id,
                venue_order_id=venue_order_id,
                venue_position_id=None,  # NETTING accounts
                trade_id=TradeId(str(data["t"])),  # Trade ID
                order_side=OrderSideParser.from_str_py(data["S"]),
                order_type=parse_order_type(data["o"]),
                last_qty=Quantity.from_str(data["l"]),
                last_px=Price.from_str(data["L"]),
                quote_currency=instrument.quote_currency,
                commission=commission,
                liquidity_side=LiquiditySide.MAKER if data["m"] else LiquiditySide.TAKER,
                ts_event=ts_event,
            )
        elif execution_type == "CANCELED" or execution_type == "EXPIRED":
            self.generate_order_canceled(
                strategy_id=strategy_id,
                instrument_id=instrument_id,
                client_order_id=client_order_id,
                venue_order_id=venue_order_id,
                ts_event=ts_event,
            )
Exemplo n.º 23
0
    def test_calculate_pnls_for_multi_currency_cash_account_btcusdt(self):
        # Arrange
        event = AccountState(
            account_id=AccountId("SIM", "001"),
            account_type=AccountType.CASH,
            base_currency=None,  # Multi-currency
            reported=True,
            balances=[
                AccountBalance(
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    Money(20.00000000, ETH),
                    Money(0.00000000, ETH),
                    Money(20.00000000, ETH),
                ),
            ],
            margins=[],
            info={},  # No default currency set
            event_id=UUID4(),
            ts_event=0,
            ts_init=0,
        )

        account = CashAccount(event)

        order1 = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.SELL,
            Quantity.from_str("0.50000000"),
        )

        fill1 = TestEventStubs.order_filled(
            order1,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("45500.00"),
        )

        position = Position(BTCUSDT_BINANCE, fill1)

        # Act
        result1 = account.calculate_pnls(
            instrument=BTCUSDT_BINANCE,
            position=position,
            fill=fill1,
        )

        order2 = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity.from_str("0.50000000"),
        )

        fill2 = TestEventStubs.order_filled(
            order2,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("45500.00"),
        )

        position.apply(fill2)

        result2 = account.calculate_pnls(
            instrument=BTCUSDT_BINANCE,
            position=position,
            fill=fill2,
        )

        # Assert
        assert result1 == [
            Money(-0.50000000, BTC),
            Money(22727.25000000, USDT)
        ]
        assert result2 == [
            Money(0.50000000, BTC),
            Money(-22772.75000000, USDT)
        ]
Exemplo n.º 24
0
    def test_market_value_when_insufficient_data_for_xrate_returns_none(self):
        # Arrange
        AccountFactory.register_calculated_account("BITMEX")

        account_id = AccountId("BITMEX", "01234")
        state = AccountState(
            account_id=account_id,
            account_type=AccountType.MARGIN,
            base_currency=BTC,
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
            ],
            info={},
            event_id=UUID4(),
            ts_event=0,
            ts_init=0,
        )

        self.portfolio.update_account(state)

        order = self.order_factory.market(
            ETHUSD_BITMEX.id,
            OrderSide.BUY,
            Quantity.from_int(100),
        )

        fill = TestStubs.event_order_filled(
            order=order,
            instrument=ETHUSD_BITMEX,
            strategy_id=StrategyId("S-1"),
            account_id=account_id,
            position_id=PositionId("P-123456"),
            last_px=Price.from_str("376.05"),
        )

        last_ethusd = QuoteTick(
            instrument_id=ETHUSD_BITMEX.id,
            bid=Price.from_str("376.05"),
            ask=Price.from_str("377.10"),
            bid_size=Quantity.from_str("16"),
            ask_size=Quantity.from_str("25"),
            ts_event=0,
            ts_init=0,
        )

        last_xbtusd = QuoteTick(
            instrument_id=BTCUSD_BITMEX.id,
            bid=Price.from_str("50000.00"),
            ask=Price.from_str("50000.00"),
            bid_size=Quantity.from_str("1"),
            ask_size=Quantity.from_str("1"),
            ts_event=0,
            ts_init=0,
        )

        position = Position(instrument=ETHUSD_BITMEX, fill=fill)

        self.portfolio.update_position(
            TestStubs.event_position_opened(position))
        self.cache.add_position(position, OMSType.HEDGING)
        self.cache.add_quote_tick(last_ethusd)
        self.cache.add_quote_tick(last_xbtusd)
        self.portfolio.update_tick(last_ethusd)
        self.portfolio.update_tick(last_xbtusd)

        # Act
        result = self.portfolio.net_exposures(BITMEX)

        # Assert
        assert result == {BTC: Money(0.00200000, BTC)}
Exemplo n.º 25
0
    async def load_all_async(self) -> None:
        """
        Load the latest Binance instruments into the provider asynchronously.

        """
        # Set async loading flag
        self._loading = True

        # Get current commission rates
        try:
            fee_res: List[Dict[str, str]] = await self._wallet.trade_fee()
            fees: Dict[str, Dict[str, str]] = {s["symbol"]: s for s in fee_res}
        except BinanceClientError:
            self._log.error(
                "Cannot load instruments: API key authentication failed "
                "(this is needed to fetch the applicable account fee tier).", )
            return

        # Get exchange info for all assets
        assets_res: Dict[str, Any] = await self._spot_market.exchange_info()
        server_time_ns: int = millis_to_nanos(assets_res["serverTime"])

        for info in assets_res["symbols"]:
            local_symbol = Symbol(info["symbol"])

            # Create base asset
            base_asset: str = info["baseAsset"]
            base_currency = Currency(
                code=base_asset,
                precision=info["baseAssetPrecision"],
                iso4217=0,  # Currently undetermined for crypto assets
                name=base_asset,
                currency_type=CurrencyType.CRYPTO,
            )

            # Create quote asset
            quote_asset: str = info["quoteAsset"]
            quote_currency = Currency(
                code=quote_asset,
                precision=info["quoteAssetPrecision"],
                iso4217=0,  # Currently undetermined for crypto assets
                name=quote_asset,
                currency_type=CurrencyType.CRYPTO,
            )

            # symbol = Symbol(base_currency.code + "/" + quote_currency.code)
            instrument_id = InstrumentId(symbol=local_symbol,
                                         venue=BINANCE_VENUE)

            # Parse instrument filters
            symbol_filters = {f["filterType"]: f for f in info["filters"]}
            price_filter = symbol_filters.get("PRICE_FILTER")
            lot_size_filter = symbol_filters.get("LOT_SIZE")
            min_notional_filter = symbol_filters.get("MIN_NOTIONAL")
            # market_lot_size_filter = symbol_filters.get("MARKET_LOT_SIZE")

            tick_size = price_filter["tickSize"].rstrip("0")
            step_size = lot_size_filter["stepSize"].rstrip("0")
            price_precision = precision_from_str(tick_size)
            size_precision = precision_from_str(step_size)
            price_increment = Price.from_str(tick_size)
            size_increment = Quantity.from_str(step_size)
            lot_size = Quantity.from_str(step_size)
            max_quantity = Quantity(float(lot_size_filter["maxQty"]),
                                    precision=size_precision)
            min_quantity = Quantity(float(lot_size_filter["minQty"]),
                                    precision=size_precision)
            min_notional = None
            if min_notional_filter is not None:
                min_notional = Money(min_notional_filter["minNotional"],
                                     currency=quote_currency)
            max_price = Price(float(price_filter["maxPrice"]),
                              precision=price_precision)
            min_price = Price(float(price_filter["minPrice"]),
                              precision=price_precision)
            pair_fees = fees.get(local_symbol.value)
            maker_fee: Decimal = Decimal(0)
            taker_fee: Decimal = Decimal(0)
            if pair_fees:
                maker_fee = Decimal(pair_fees["makerCommission"])
                taker_fee = Decimal(pair_fees["takerCommission"])

            # Create instrument
            instrument = CurrencySpot(
                instrument_id=instrument_id,
                local_symbol=local_symbol,
                base_currency=base_currency,
                quote_currency=quote_currency,
                price_precision=price_precision,
                size_precision=size_precision,
                price_increment=price_increment,
                size_increment=size_increment,
                lot_size=lot_size,
                max_quantity=max_quantity,
                min_quantity=min_quantity,
                max_notional=None,
                min_notional=min_notional,
                max_price=max_price,
                min_price=min_price,
                margin_init=Decimal(0),
                margin_maint=Decimal(0),
                maker_fee=maker_fee,
                taker_fee=taker_fee,
                ts_event=server_time_ns,
                ts_init=time.time_ns(),
                info=info,
            )

            self.add_currency(currency=base_currency)
            self.add_currency(currency=quote_currency)
            self.add(instrument=instrument)

        # Set async loading flags
        self._loading = False
        self._loaded = True
Exemplo n.º 26
0
    def default_fx_ccy(symbol: str, venue: Venue = None) -> CurrencySpot:
        """
        Return a default FX currency pair instrument from the given instrument_id.

        Parameters
        ----------
        symbol : str
            The currency pair symbol.
        venue : Venue
            The currency pair venue.

        Returns
        -------
        CurrencySpot

        Raises
        ------
        ValueError
            If `symbol` length is not in range [6, 7].

        """
        if venue is None:
            venue = Venue("SIM")
        PyCondition.valid_string(symbol, "symbol")
        PyCondition.in_range_int(len(symbol), 6, 7, "len(symbol)")

        instrument_id = InstrumentId(
            symbol=Symbol(symbol),
            venue=venue,
        )

        base_currency = symbol[:3]
        quote_currency = symbol[-3:]

        # Check tick precision of quote currency
        if quote_currency == "JPY":
            price_precision = 3
        else:
            price_precision = 5

        return CurrencySpot(
            instrument_id=instrument_id,
            local_symbol=Symbol(symbol),
            base_currency=Currency.from_str(base_currency),
            quote_currency=Currency.from_str(quote_currency),
            price_precision=price_precision,
            size_precision=0,
            price_increment=Price(1 / 10**price_precision, price_precision),
            size_increment=Quantity.from_int(1),
            lot_size=Quantity.from_str("1000"),
            max_quantity=Quantity.from_str("1e7"),
            min_quantity=Quantity.from_str("1000"),
            max_price=None,
            min_price=None,
            max_notional=Money(50000000.00, USD),
            min_notional=Money(1000.00, USD),
            margin_init=Decimal("0.03"),
            margin_maint=Decimal("0.03"),
            maker_fee=Decimal("0.00002"),
            taker_fee=Decimal("0.00002"),
            ts_event=0,
            ts_init=0,
        )
Exemplo n.º 27
0
    def test_handle_trade_tick_when_volume_beyond_threshold_sends_bars_to_handler(
            self):
        # Arrange
        bar_store = ObjectStorer()
        handler = bar_store.store
        instrument_id = TestStubs.audusd_id()
        bar_spec = BarSpecification(100000, BarAggregation.VALUE,
                                    PriceType.LAST)
        bar_type = BarType(instrument_id, bar_spec)
        aggregator = ValueBarAggregator(
            AUDUSD_SIM,
            bar_type,
            handler,
            Logger(TestClock()),
        )

        tick1 = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("20.00001"),
            size=Quantity.from_str("3000.00"),
            aggressor_side=AggressorSide.BUY,
            match_id="123456",
            ts_event_ns=0,
            ts_recv_ns=0,
        )

        tick2 = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("20.00002"),
            size=Quantity.from_str("4000.00"),
            aggressor_side=AggressorSide.BUY,
            match_id="123457",
            ts_event_ns=0,
            ts_recv_ns=0,
        )

        tick3 = TradeTick(
            instrument_id=AUDUSD_SIM.id,
            price=Price.from_str("20.00000"),
            size=Quantity.from_str("5000.00"),
            aggressor_side=AggressorSide.BUY,
            match_id="123458",
            ts_event_ns=0,
            ts_recv_ns=0,
        )

        # Act
        aggregator.handle_trade_tick(tick1)
        aggregator.handle_trade_tick(tick2)
        aggregator.handle_trade_tick(tick3)

        # Assert
        self.assertEqual(2, len(bar_store.get_store()))
        self.assertEqual(Price.from_str("20.00001"),
                         bar_store.get_store()[0].open)
        self.assertEqual(Price.from_str("20.00002"),
                         bar_store.get_store()[0].high)
        self.assertEqual(Price.from_str("20.00001"),
                         bar_store.get_store()[0].low)
        self.assertEqual(Price.from_str("20.00002"),
                         bar_store.get_store()[0].close)
        self.assertEqual(Quantity.from_str("5000.00"),
                         bar_store.get_store()[0].volume)
        self.assertEqual(Price.from_str("20.00002"),
                         bar_store.get_store()[1].open)
        self.assertEqual(Price.from_str("20.00002"),
                         bar_store.get_store()[1].high)
        self.assertEqual(Price.from_str("20.00000"),
                         bar_store.get_store()[1].low)
        self.assertEqual(Price.from_str("20.00000"),
                         bar_store.get_store()[1].close)
        self.assertEqual(Quantity.from_str("5000.00"),
                         bar_store.get_store()[1].volume)
        self.assertEqual(
            Decimal("40000.11000"),
            aggregator.get_cumulative_value())  # TODO: WIP - Should be 40000
Exemplo n.º 28
0
    def _handle_order_trade_update(self, msg: BinanceFuturesOrderUpdateMsg):
        data: BinanceFuturesOrderData = msg.o
        instrument_id: InstrumentId = self._get_cached_instrument_id(data.s)
        client_order_id = ClientOrderId(data.c) if data.c != "" else None
        venue_order_id = VenueOrderId(str(data.i))
        ts_event = millis_to_nanos(msg.T)

        # Fetch strategy ID
        strategy_id: StrategyId = self._cache.strategy_id_for_order(
            client_order_id)
        if strategy_id is None:
            if strategy_id is None:
                self._generate_external_order_status(
                    instrument_id,
                    client_order_id,
                    venue_order_id,
                    msg.o,
                    ts_event,
                )
                return

        if data.x == BinanceFuturesExecutionType.NEW:
            self.generate_order_accepted(
                strategy_id=strategy_id,
                instrument_id=instrument_id,
                client_order_id=client_order_id,
                venue_order_id=venue_order_id,
                ts_event=ts_event,
            )
        elif data.x == BinanceFuturesExecutionType.TRADE:
            instrument: Instrument = self._instrument_provider.find(
                instrument_id=instrument_id)

            # Determine commission
            if data.N is not None:
                commission = Money.from_str(f"{data.n} {data.N}")
            else:
                # Commission in margin collateral currency
                commission = Money(0, instrument.quote_currency)

            self.generate_order_filled(
                strategy_id=strategy_id,
                instrument_id=instrument_id,
                client_order_id=client_order_id,
                venue_order_id=venue_order_id,
                venue_position_id=PositionId(
                    f"{instrument_id}-{data.ps.value}"),
                trade_id=TradeId(str(data.t)),
                order_side=OrderSide.BUY
                if data.S == BinanceOrderSide.BUY else OrderSide.SELL,
                order_type=parse_order_type(data.o),
                last_qty=Quantity.from_str(data.l),
                last_px=Price.from_str(data.L),
                quote_currency=instrument.quote_currency,
                commission=commission,
                liquidity_side=LiquiditySide.MAKER
                if data.m else LiquiditySide.TAKER,
                ts_event=ts_event,
            )
        elif data.x == BinanceFuturesExecutionType.CANCELED:
            self.generate_order_canceled(
                strategy_id=strategy_id,
                instrument_id=instrument_id,
                client_order_id=client_order_id,
                venue_order_id=venue_order_id,
                ts_event=ts_event,
            )
        elif data.x == BinanceFuturesExecutionType.EXPIRED:
            self.generate_order_expired(
                strategy_id=strategy_id,
                instrument_id=instrument_id,
                client_order_id=client_order_id,
                venue_order_id=venue_order_id,
                ts_event=ts_event,
            )
Exemplo n.º 29
0
 def test_str_and_to_str(self, value, expected):
     # Arrange
     # Act
     # Assert
     assert Quantity.from_str(value).to_str() == expected
Exemplo n.º 30
0
    def test_update_positions(self):
        # Arrange
        state = AccountState(
            account_id=AccountId("BINANCE", "01234"),
            account_type=AccountType.CASH,
            base_currency=None,  # Multi-currency account
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    ETH,
                    Money(20.00000000, ETH),
                    Money(0.00000000, ETH),
                    Money(20.00000000, ETH),
                ),
            ],
            info={},
            event_id=uuid4(),
            updated_ns=0,
            timestamp_ns=0,
        )

        self.exec_engine.process(state)

        # Create a closed position
        order1 = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity.from_str("10.50000000"),
        )

        order2 = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.SELL,
            Quantity.from_str("10.50000000"),
        )

        self.exec_engine.cache.add_order(order1, PositionId.null())
        self.exec_engine.cache.add_order(order2, PositionId.null())

        # Push states to ACCEPTED
        order1.apply(TestStubs.event_order_submitted(order1))
        self.exec_engine.cache.update_order(order1)
        order1.apply(TestStubs.event_order_accepted(order1))
        self.exec_engine.cache.update_order(order1)

        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-1"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("25000.00"),
        )

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-1"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("25000.00"),
        )

        position1 = Position(instrument=BTCUSDT_BINANCE, fill=fill1)
        position1.apply(fill2)

        order3 = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity.from_str("10.00000000"),
        )

        fill3 = TestStubs.event_order_filled(
            order3,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-2"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("25000.00"),
        )

        position2 = Position(instrument=BTCUSDT_BINANCE, fill=fill3)

        # Update the last quote
        last = QuoteTick(
            BTCUSDT_BINANCE.id,
            Price.from_str("25001.00"),
            Price.from_str("25002.00"),
            Quantity.from_int(1),
            Quantity.from_int(1),
            0,
            0,
        )

        # Act
        self.cache.add_position(position1)
        self.cache.add_position(position2)
        self.portfolio.initialize_positions()
        self.portfolio.update_tick(last)

        # Assert
        self.assertTrue(self.portfolio.is_net_long(BTCUSDT_BINANCE.id))