def serialize(event: PositionEvent):
    data = {
        k: v
        for k, v in event.to_dict(event).items() if k not in ("order_fill", )
    }
    caster = {
        "net_qty": float,
        "quantity": float,
        "peak_qty": float,
        "avg_px_open": float,
        "last_qty": float,
        "last_px": float,
        "avg_px_close": try_float,
        "realized_points": try_float,
        "realized_return": try_float,
    }
    values = {k: caster[k](v) if k in caster else v
              for k, v in data.items()}  # type: ignore
    if "realized_pnl" in values:
        realized = Money.from_str(values["realized_pnl"])
        values["realized_pnl"] = realized.as_double()
    if "unrealized_pnl" in values:
        unrealized = Money.from_str(values["unrealized_pnl"])
        values["unrealized_pnl"] = unrealized.as_double()
    return values
    def test_from_str_when_malformed_raises_value_error(self):
        # Arrange
        value = "@"

        # Act, Assert
        with pytest.raises(ValueError):
            Money.from_str(value)
Esempio n. 3
0
    def _create_engine(
        self,
        config: BacktestEngineConfig,
        venue_configs: List[BacktestVenueConfig],
        data_configs: List[BacktestDataConfig],
    ):
        # Build the backtest engine
        engine = BacktestEngine(config=config)

        # Add instruments
        for config in data_configs:
            if is_nautilus_class(config.data_type):
                instruments = config.catalog().instruments(
                    instrument_ids=config.instrument_id, as_nautilus=True)
                for instrument in instruments or []:
                    engine.add_instrument(instrument)

        # Add venues
        for config in venue_configs:
            engine.add_venue(
                venue=Venue(config.name),
                venue_type=VenueType[config.venue_type],
                oms_type=OMSType[config.oms_type],
                account_type=AccountType[config.account_type],
                base_currency=Currency.from_str(config.base_currency),
                starting_balances=[
                    Money.from_str(m) for m in config.starting_balances
                ],
                book_type=BookTypeParser.from_str_py(config.book_type),
            )
        return engine
    def test_from_str_given_valid_strings_returns_expected_result(
        self,
        value,
        expected,
    ):
        # Arrange, Act
        result = Money.from_str(value)

        # Assert
        assert result == expected
Esempio n. 5
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,
            )
    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,
            )