def test_serialize_and_deserialize_position_events_closed(
            self, position_func):
        instrument = TestInstrumentProvider.default_fx_ccy("GBPUSD")

        open_order = self.order_factory.market(
            instrument.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )
        open_fill = TestStubs.event_order_filled(
            open_order,
            instrument=instrument,
            position_id=PositionId("P-3"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("1.00000"),
        )
        close_order = self.order_factory.market(
            instrument.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
        )
        close_fill = TestStubs.event_order_filled(
            close_order,
            instrument=instrument,
            position_id=PositionId("P-3"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("1.20000"),
        )

        position = Position(instrument=instrument, fill=open_fill)
        position.apply(close_fill)

        event = position_func(position=position)
        self._test_serialization(obj=event)
    def test_can_update_position_for_closed_position(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000))
        position_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order1, self.strategy.id, position_id)

        order1_filled = TestStubs.event_order_filled(order1, fill_price=Price(1.00001, 5))
        order1.apply(order1_filled)
        position = Position(position_id, order1.last_event)
        self.database.add_position(position, self.strategy.id)

        order2 = self.strategy.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.SELL,
            Quantity(100000))
        order2_filled = TestStubs.event_order_filled(order2, fill_price=Price(1.00001, 5))
        position.apply(order2_filled)

        # Act
        self.database.update_position(position)

        # Assert
        self.assertTrue(self.database.position_exists(position.id))
        self.assertTrue(position.id in self.database.get_position_ids())
        self.assertTrue(position.id in self.database.get_positions())
        self.assertTrue(position.id in self.database.get_positions_closed(self.strategy.id))
        self.assertTrue(position.id in self.database.get_positions_closed())
        self.assertTrue(position.id not in self.database.get_positions_open(self.strategy.id))
        self.assertTrue(position.id not in self.database.get_positions_open())
        self.assertEqual(position, self.database.get_position_for_order(order1.id))
    def test_position_filled_with_no_change_returns_expected_attributes(self):
        # Arrange
        order1 = self.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000))

        order2 = self.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.SELL,
            Quantity(100000))

        fill1 = TestStubs.event_order_filled(order1)

        position = Position(fill1)

        fill2 = TestStubs.event_order_filled(
            order2,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00000"),
        )

        last = QuoteTick(
            AUDUSD_FXCM,
            Price("1.00050"),
            Price("1.00048"),
            Quantity(1),
            Quantity(1),
            UNIX_EPOCH,
        )

        # Act
        position.apply(fill2)

        # Assert
        self.assertEqual(Quantity(), position.quantity)
        self.assertEqual(PositionSide.FLAT, position.side)
        self.assertEqual(UNIX_EPOCH, position.opened_time)
        self.assertEqual(1.0, position.avg_open_price)
        self.assertEqual(2, position.event_count())
        self.assertEqual({order1.cl_ord_id, order2.cl_ord_id}, position.cl_ord_ids())
        self.assertEqual({
            ExecutionId("E-19700101-000000-001-001-1"),
            ExecutionId("E-19700101-000000-001-001-2")
        },
            position.execution_ids(),
        )
        self.assertEqual(UNIX_EPOCH, position.closed_time)
        self.assertEqual(1.0, position.avg_close_price)
        self.assertFalse(position.is_long())
        self.assertFalse(position.is_short())
        self.assertTrue(position.is_closed())
        self.assertEqual(0.0, position.realized_points)
        self.assertEqual(0.0, position.realized_return)
        self.assertEqual(Money(0, USD), position.realized_pnl)
        self.assertEqual(Money(0, USD), position.unrealized_pnl(last))
        self.assertEqual(Money(0, USD), position.total_pnl(last))
Example #4
0
    def test_generate_positions_report(self):
        # Arrange
        report_provider = ReportProvider()

        order1 = self.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        order2 = self.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
        )

        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00010"),
        )

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-123457"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00010"),
        )

        position1 = Position(fill1)
        position1.apply(fill2)

        position2 = Position(fill1)
        position2.apply(fill2)

        positions = [position1, position2]

        # Act
        report = report_provider.generate_positions_report(positions)

        # Assert
        self.assertEqual(2, len(report))
        self.assertEqual("position_id", report.index.name)
        self.assertEqual(position1.id.value, report.index[0])
        self.assertEqual("AUD/USD", report.iloc[0]["symbol"])
        self.assertEqual("BUY", report.iloc[0]["entry"])
        self.assertEqual(100000, report.iloc[0]["peak_quantity"])
        self.assertEqual(1.0001, report.iloc[0]["avg_open"])
        self.assertEqual(1.0001, report.iloc[0]["avg_close"])
        self.assertEqual(UNIX_EPOCH, report.iloc[0]["opened_time"])
        self.assertEqual(UNIX_EPOCH, report.iloc[0]["closed_time"])
        self.assertEqual(0, report.iloc[0]["realized_points"])
        self.assertEqual(0, report.iloc[0]["realized_return"])
    def test_position_partial_fills_with_sell_order_returns_expected_attributes(
            self):
        # Arrange
        order = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity(100000),
        )

        fill1 = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            execution_id=ExecutionId("1"),
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            last_px=Price("1.00001"),
            last_qty=Quantity(50000),
        )

        fill2 = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            execution_id=ExecutionId("2"),
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            last_px=Price("1.00002"),
            last_qty=Quantity(50000),
        )

        position = Position(fill=fill1)

        last = Price("1.00050")

        # Act
        position.apply(fill2)

        # Assert
        self.assertEqual(Quantity(100000), position.quantity)
        self.assertEqual(PositionSide.SHORT, position.side)
        self.assertEqual(0, position.opened_timestamp_ns)
        self.assertEqual(Decimal("1.000015"), position.avg_px_open)
        self.assertEqual(2, position.event_count)
        self.assertFalse(position.is_long)
        self.assertTrue(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(-4.00, USD), position.realized_pnl)
        self.assertEqual(Money(-48.50, USD), position.unrealized_pnl(last))
        self.assertEqual(Money(-52.50, USD), position.total_pnl(last))
        self.assertEqual([Money(4.00, USD)], position.commissions())
        self.assertEqual(Money(4.00, USD), position.commission)
        self.assertEqual("Position(SHORT 100,000 AUD/USD.SIM, id=P-123456)",
                         repr(position))
    def test_generate_positions_report(self):
        # Arrange
        order1 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        order2 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
        )

        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("1.00010"),
        )

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-123457"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("1.00010"),
        )

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

        position2 = Position(instrument=AUDUSD_SIM, fill=fill1)
        position2.apply(fill2)

        positions = [position1, position2]

        # Act
        report = ReportProvider.generate_positions_report(positions)

        # Assert
        assert len(report) == 2
        assert report.index.name == "position_id"
        assert report.index[0] == position1.id.value
        assert report.iloc[0]["instrument_id"] == "AUD/USD.SIM"
        assert report.iloc[0]["entry"] == "BUY"
        assert report.iloc[0]["side"] == "FLAT"
        assert report.iloc[0]["peak_qty"] == "100000"
        assert report.iloc[0]["avg_px_open"] == "1.00010"
        assert report.iloc[0]["avg_px_close"] == "1.00010"
        assert report.iloc[0]["ts_opened"] == UNIX_EPOCH
        assert report.iloc[0]["ts_closed"] == UNIX_EPOCH
        assert report.iloc[0]["realized_points"] == "0.00000"
        assert report.iloc[0]["realized_return"] == "0.00000"
Example #7
0
    def test_position_partial_fills_with_sell_order_returns_expected_attributes(
            self):
        # Arrange
        order = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
        )

        fill1 = TestEventStubs.order_filled(
            order,
            instrument=AUDUSD_SIM,
            trade_id=TradeId("1"),
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("1.00001"),
            last_qty=Quantity.from_int(50000),
        )

        fill2 = TestEventStubs.order_filled(
            order,
            instrument=AUDUSD_SIM,
            trade_id=TradeId("2"),
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("1.00002"),
            last_qty=Quantity.from_int(50000),
        )

        position = Position(instrument=AUDUSD_SIM, fill=fill1)

        last = Price.from_str("1.00050")

        # Act
        position.apply(fill2)

        # Assert
        assert position.quantity == Quantity.from_int(100000)
        assert position.side == PositionSide.SHORT
        assert position.ts_opened == 0
        assert position.avg_px_open == Decimal("1.000015")
        assert position.event_count == 2
        assert not position.is_long
        assert 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(-4.00, USD)
        assert position.unrealized_pnl(last) == Money(-48.50, USD)
        assert position.total_pnl(last) == Money(-52.50, USD)
        assert position.commissions() == [Money(4.00, USD)]
        assert repr(
            position) == "Position(SHORT 100_000 AUD/USD.SIM, id=P-123456)"
    def test_position_long_with_multiple_filled_orders_returns_expected_attributes(self):
        # Arrange
        order1 = self.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000),
        )

        order2 = self.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000),
        )

        order3 = self.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.SELL,
            Quantity(200000),
        )

        fill1 = TestStubs.event_order_filled(order1, PositionId("P-123456"), StrategyId("S", "001"))
        fill2 = TestStubs.event_order_filled(order2, PositionId("P-123456"), StrategyId("S", "001"), fill_price=Price("1.00001"))
        fill3 = TestStubs.event_order_filled(order3, PositionId("P-123456"), StrategyId("S", "001"), fill_price=Price("1.00010"))

        last = QuoteTick(
            AUDUSD_FXCM,
            Price("1.00050"),
            Price("1.00048"),
            Quantity(1),
            Quantity(1),
            UNIX_EPOCH,
        )

        # Act
        position = Position(fill1)
        position.apply(fill2)
        position.apply(fill3)

        # Assert
        self.assertEqual(Quantity(), position.quantity)
        self.assertEqual(PositionSide.FLAT, position.side)
        self.assertEqual(UNIX_EPOCH, position.opened_time)
        self.assertEqual(1.000005, position.avg_open_price)
        self.assertEqual(3, position.event_count())
        self.assertEqual({order1.cl_ord_id, order2.cl_ord_id, order3.cl_ord_id}, position.cl_ord_ids())
        self.assertEqual(UNIX_EPOCH, position.closed_time)
        self.assertEqual(1.0001, position.avg_close_price)
        self.assertFalse(position.is_long())
        self.assertFalse(position.is_short())
        self.assertTrue(position.is_closed())
        self.assertEqual(Money(19.00, USD), position.realized_pnl)
        self.assertEqual(Money(0, USD), position.unrealized_pnl(last))
        self.assertEqual(Money(19.00, USD), position.total_pnl(last))
def nautilus_objects() -> List[Any]:
    """A list of nautilus instances for testing serialization"""
    instrument = TestInstrumentProvider.default_fx_ccy("AUD/USD")
    position_id = PositionId("P-001")
    buy = TestExecStubs.limit_order()
    buy_submitted, buy_accepted, buy_filled = _make_order_events(
        buy,
        instrument=instrument,
        position_id=position_id,
        trade_id=TradeId("BUY"),
    )
    sell = TestExecStubs.limit_order(order_side=OrderSide.SELL)
    _, _, sell_filled = _make_order_events(
        sell,
        instrument=instrument,
        position_id=position_id,
        trade_id=TradeId("SELL"),
    )
    open_position = Position(instrument=instrument, fill=buy_filled)
    closed_position = Position(instrument=instrument, fill=buy_filled)
    closed_position.apply(sell_filled)

    return [
        TestDataStubs.ticker(),
        TestDataStubs.quote_tick_5decimal(),
        TestDataStubs.trade_tick_5decimal(),
        TestDataStubs.bar_5decimal(),
        TestDataStubs.venue_status_update(),
        TestDataStubs.instrument_status_update(),
        TestEventStubs.component_state_changed(),
        TestEventStubs.trading_state_changed(),
        TestEventStubs.betting_account_state(),
        TestEventStubs.cash_account_state(),
        TestEventStubs.margin_account_state(),
        # ORDERS
        TestEventStubs.order_accepted(buy),
        TestEventStubs.order_rejected(buy),
        TestEventStubs.order_pending_update(buy_accepted),
        TestEventStubs.order_pending_cancel(buy_accepted),
        TestEventStubs.order_filled(
            order=buy,
            instrument=instrument,
            position_id=open_position.id,
        ),
        TestEventStubs.order_canceled(buy_accepted),
        TestEventStubs.order_expired(buy),
        TestEventStubs.order_triggered(buy),
        # POSITIONS
        TestEventStubs.position_opened(open_position),
        TestEventStubs.position_changed(open_position),
        TestEventStubs.position_closed(closed_position),
    ]
    def test_position_partial_fills_with_sell_order_returns_expected_attributes(self):
        # Arrange
        order = self.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.SELL,
            Quantity(100000))

        fill1 = TestStubs.event_order_filled(
            order,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00001"),
            filled_qty=Quantity(50000),
            leaves_qty=Quantity(50000),
        )

        fill2 = TestStubs.event_order_filled(
            order,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00002"),
            filled_qty=Quantity(50000),
            leaves_qty=Quantity(),
        )

        position = Position(fill1)

        last = QuoteTick(
            AUDUSD_FXCM,
            Price("1.00050"),
            Price("1.00048"),
            Quantity(1),
            Quantity(1),
            UNIX_EPOCH)

        # Act
        position.apply(fill2)

        # Assert
        self.assertEqual(Quantity(100000), position.quantity)
        self.assertEqual(PositionSide.SHORT, position.side)
        self.assertEqual(UNIX_EPOCH, position.opened_time)
        self.assertEqual(1.000015, position.avg_open_price)
        self.assertEqual(2, position.event_count())
        self.assertFalse(position.is_long())
        self.assertTrue(position.is_short())
        self.assertFalse(position.is_closed())
        self.assertEqual(0.0, position.realized_points)
        self.assertEqual(0.0, position.realized_return)
        self.assertEqual(Money(0, USD), position.realized_pnl)
        self.assertEqual(Money(-46.50, USD), position.unrealized_pnl(last))
        self.assertEqual(Money(-46.50, USD), position.total_pnl(last))
    def test_position_changed_event_to_from_dict_and_str_repr(self):
        # Arrange
        order1 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

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

        order2 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(50000),
        )

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("1.00011"),
        )

        position = Position(instrument=AUDUSD_SIM, fill=fill1)
        position.apply(fill2)

        uuid = UUID4()
        event = PositionChanged.create(position, fill2, uuid, 0)

        # Act, Assert
        assert PositionChanged.from_dict(
            PositionChanged.to_dict(event)) == event
        assert (
            str(event) ==
            "PositionChanged(instrument_id=AUD/USD.SIM, position_id=P-123456, account_id=SIM-000, from_order=O-19700101-000000-000-001-1, strategy_id=S-001, entry=BUY, side=LONG, net_qty=50_000, quantity=50_000, peak_qty=100_000, currency=USD, avg_px_open=1.00001, avg_px_close=1.00011, realized_points=0.00010, realized_return=0.00010, realized_pnl=2.00 USD, unrealized_pnl=5.00 USD, ts_opened=0, ts_last=0, ts_closed=0, duration_ns=0)"  # noqa
        )
        assert (
            repr(event) ==
            f"PositionChanged(trader_id=TESTER-000, strategy_id=S-001, instrument_id=AUD/USD.SIM, position_id=P-123456, account_id=SIM-000, from_order=O-19700101-000000-000-001-1, strategy_id=S-001, entry=BUY, side=LONG, net_qty=50_000, quantity=50_000, peak_qty=100_000, currency=USD, avg_px_open=1.00001, avg_px_close=1.00011, realized_points=0.00010, realized_return=0.00010, realized_pnl=2.00 USD, unrealized_pnl=5.00 USD, ts_opened=0, ts_last=0, ts_closed=0, duration_ns=0, event_id={uuid})"  # noqa
        )
Example #12
0
    def test_update_position_for_closed_position(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000))
        position_id = PositionId('P-1')
        self.database.add_order(order1, position_id)

        order1.apply(TestStubs.event_order_submitted(order1))
        self.database.update_order(order1)

        order1.apply(TestStubs.event_order_accepted(order1))
        self.database.update_order(order1)

        order1.apply(TestStubs.event_order_filled(order1, position_id=position_id, fill_price=Price("1.00001")))
        self.database.update_order(order1)

        # Act
        position = Position(order1.last_event())
        self.database.add_position(position)

        order2 = self.strategy.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.SELL,
            Quantity(100000))
        self.database.add_order(order2, position_id)

        order2.apply(TestStubs.event_order_submitted(order2))
        self.database.update_order(order2)

        order2.apply(TestStubs.event_order_accepted(order2))
        self.database.update_order(order2)

        filled = TestStubs.event_order_filled(order2, position_id=position_id, fill_price=Price("1.00001"))
        order2.apply(filled)
        self.database.update_order(order2)

        position.apply(filled)

        # Act
        self.database.update_position(position)

        # Assert
        self.assertEqual(position, self.database.load_position(position.id))
Example #13
0
    def test_calculate_given_one_long_one_short_returns_expected(self):
        # Arrange
        stat = LongRatio()

        order1 = self.order_factory.market(
            ETHUSD_FTX.id,
            OrderSide.BUY,
            Quantity.from_int(1),
        )

        order2 = self.order_factory.market(
            ETHUSD_FTX.id,
            OrderSide.SELL,
            Quantity.from_int(1),
        )

        fill1 = TestEventStubs.order_filled(
            order1,
            instrument=ETHUSD_FTX,
            position_id=PositionId("P-1"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_int(10_000),
        )

        fill2 = TestEventStubs.order_filled(
            order2,
            instrument=ETHUSD_FTX,
            position_id=PositionId("P-2"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_int(10_000),
        )

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

        position2 = Position(instrument=ETHUSD_FTX, fill=fill2)
        position2.apply(fill1)

        data = [position1, position2]

        # Act
        result = stat.calculate_from_positions(data)

        # Assert
        assert result == "0.50"
Example #14
0
    def test_serialize_and_deserialize_position_closed_events(self):
        # Arrange
        order1 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

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

        order2 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
        )

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

        position = Position(instrument=AUDUSD_SIM, fill=fill1)
        position.apply(fill2)

        uuid = UUID4()
        event = PositionClosed.create(position, fill2, uuid, 0)

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

        # Assert
        assert deserialized == event
    def test_calculate_unrealized_pnl_for_long(self):
        # Arrange
        order1 = self.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity("2.000000"),
        )

        order2 = self.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity("2.000000"),
        )

        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("10500.00"),
        )

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("10500.00"),
        )

        position = Position(fill1)
        position.apply(fill2)

        # Act
        pnl = position.unrealized_pnl(Price("11505.60"))

        # Assert
        self.assertEqual(Money("4022.40000000", USDT), pnl)
        self.assertEqual(Money("-42.00000000", USDT), position.realized_pnl)
        self.assertEqual([Money("42.00000000", USDT)], position.commissions())
        self.assertEqual(Money("42.00000000", USDT), position.commission)
    def test_calculate_pnls_partially_closed(self):
        # Arrange
        event = self._make_account_state(starting_balance=1000.0)
        account = BettingAccount(event)
        fill1 = self._make_fill(price="0.50", volume=100, side="BUY")
        fill2 = self._make_fill(price="0.80", volume=100, side="SELL")

        position = Position(self.instrument, fill1)
        position.apply(fill2)

        # Act
        result = account.calculate_pnls(
            instrument=self.instrument,
            position=position,
            fill=fill2,
        )

        # Assert
        # TODO - this should really be 75 GBP given the position (but we are currently not using position?)
        # assert result == [Money("75.00", GBP)]
        assert result == [Money("80.00", GBP)]
Example #17
0
    def test_calculate_unrealized_pnl_for_long(self):
        # Arrange
        order1 = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity.from_str("2.000000"),
        )

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

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

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

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

        # Act
        pnl = position.unrealized_pnl(Price.from_str("11505.60"))

        # Assert
        assert pnl == Money(4022.40000000, USDT)
        assert position.realized_pnl == Money(-42.00000000, USDT)
        assert position.commissions() == [Money(42.00000000, USDT)]
    def test_get_realized_pnls_when_all_flat_positions_returns_expected_series(
            self):
        # Arrange
        order1 = self.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        order2 = self.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
        )

        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
        )

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00000"),
        )

        position1 = Position(fill1)
        position1.apply(fill2)

        position2 = Position(fill1)
        position2.apply(fill2)

        self.analyzer.add_positions([position1, position2])

        # Act

        # Assert
        self.assertTrue(all(self.analyzer.get_realized_pnls()))
Example #19
0
    def test_get_realized_pnls_when_all_flat_positions_returns_expected_series(
            self):
        # Arrange
        order1 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        order2 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
        )

        order3 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        order4 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
        )

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

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

        fill3 = TestStubs.event_order_filled(
            order3,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-2"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("1.00000"),
        )

        fill4 = TestStubs.event_order_filled(
            order4,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-2"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("1.00020"),
        )

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

        position2 = Position(instrument=AUDUSD_SIM, fill=fill3)
        position2.apply(fill4)

        self.analyzer.add_positions([position1, position2])

        # Act
        result = self.analyzer.realized_pnls(USD)

        # Assert
        assert len(result) == 2
        assert result["P-1"] == 6.0
        assert result["P-2"] == 16.0
Example #20
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)
        ]
Example #21
0
    def position_which_is_closed(position_id, close_price=None) -> Position:

        if close_price is None:
            close_price = Price("1.0001")

        order_factory = OrderFactory(
            strategy_id=StrategyId("S", "001"),
            id_tag_trader=IdTag("001"),
            id_tag_strategy=IdTag("001"),
        )

        order = order_factory.market(
            TestStubs.symbol_audusd_fxcm(),
            OrderSide.SELL,
            Quantity(100000),
        )

        filled1 = OrderFilled(
            TestStubs.account_id(),
            order.cl_ord_id,
            OrderId("1"),
            ExecutionId(order.cl_ord_id.value.replace('O', 'E')),
            position_id,
            StrategyId("S", "1"),
            order.symbol,
            order.side,
            order.quantity,
            Quantity(),
            close_price,
            Money(0, USD),
            LiquiditySide.TAKER,
            USD,  # Stub event
            USD,  # Stub event
            UNIX_EPOCH + timedelta(minutes=5),
            uuid4(),
            UNIX_EPOCH + timedelta(minutes=5),
        )

        filled2 = OrderFilled(
            TestStubs.account_id(),
            order.cl_ord_id,
            OrderId("2"),
            ExecutionId(order.cl_ord_id.value.replace('O', 'E')),
            position_id,
            StrategyId("S", "1"),
            order.symbol,
            OrderSide.BUY,
            order.quantity,
            Quantity(),
            close_price,
            Money(0, USD),
            LiquiditySide.TAKER,
            USD,  # Stub event
            USD,  # Stub event
            UNIX_EPOCH + timedelta(minutes=5),
            uuid4(),
            UNIX_EPOCH + timedelta(minutes=5),
        )

        position = Position(filled1)
        position.apply(filled2)

        return position
    def test_get_realized_pnls_when_all_flat_positions_returns_expected_series(
            self):
        # Arrange
        order1 = self.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        order2 = self.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
        )

        order3 = self.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        order4 = self.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
        )

        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-1"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00000"),
        )

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-1"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00010"),
        )

        fill3 = TestStubs.event_order_filled(
            order3,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-2"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00000"),
        )

        fill4 = TestStubs.event_order_filled(
            order4,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-2"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00020"),
        )

        position1 = Position(fill1)
        position1.apply(fill2)

        position2 = Position(fill3)
        position2.apply(fill4)

        self.analyzer.add_positions([position1, position2])

        # Act
        result = self.analyzer.get_realized_pnls()

        # Assert
        self.assertEqual(2, len(result))
        self.assertEqual(6.0, result['P-1'])
        self.assertEqual(16.0, result['P-2'])
Example #23
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))
Example #24
0
    def test_closing_position_updates_portfolio(self):
        # Arrange
        state = AccountState(
            account_id=AccountId("SIM", "01234"),
            account_type=AccountType.MARGIN,
            base_currency=USD,
            reported=True,
            balances=[
                AccountBalance(
                    USD,
                    Money(1_000_000, USD),
                    Money(0, USD),
                    Money(1_000_000, USD),
                ),
            ],
            info={},
            event_id=uuid4(),
            updated_ns=0,
            timestamp_ns=0,
        )

        self.exec_engine.process(state)

        order1 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

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

        position = Position(instrument=AUDUSD_SIM, fill=fill1)
        self.exec_engine.cache.add_position(position)
        self.portfolio.update_position(
            TestStubs.event_position_opened(position))

        order2 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
        )

        order2_filled = TestStubs.event_order_filled(
            order2,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("1.00010"),
        )

        position.apply(order2_filled)
        self.exec_engine.cache.update_position(position)

        # Act
        self.portfolio.update_position(
            TestStubs.event_position_closed(position))

        # Assert
        self.assertEqual({}, self.portfolio.net_exposures(SIM))
        self.assertEqual({}, self.portfolio.unrealized_pnls(SIM))
        self.assertEqual({}, self.portfolio.maint_margins(SIM))
        self.assertEqual(Money(0, USD),
                         self.portfolio.net_exposure(AUDUSD_SIM.id))
        self.assertEqual(Money(0, USD),
                         self.portfolio.unrealized_pnl(AUDUSD_SIM.id))
        self.assertEqual(Decimal(0),
                         self.portfolio.net_position(AUDUSD_SIM.id))
        self.assertFalse(self.portfolio.is_net_long(AUDUSD_SIM.id))
        self.assertFalse(self.portfolio.is_net_short(AUDUSD_SIM.id))
        self.assertTrue(self.portfolio.is_flat(AUDUSD_SIM.id))
        self.assertTrue(self.portfolio.is_completely_flat())
    def test_position_realised_pnl_with_interleaved_orders_sides(self):
        # Arrange
        order1 = self.order_factory.market(
            BTCUSD_BINANCE,
            OrderSide.BUY,
            Quantity(12),
        )

        order2 = self.order_factory.market(
            BTCUSD_BINANCE,
            OrderSide.BUY,
            Quantity(17),
        )

        order3 = self.order_factory.market(
            BTCUSD_BINANCE,
            OrderSide.SELL,
            Quantity(9),
        )

        order4 = self.order_factory.market(
            BTCUSD_BINANCE,
            OrderSide.BUY,
            Quantity(3),
        )

        order5 = self.order_factory.market(
            BTCUSD_BINANCE,
            OrderSide.SELL,
            Quantity(4),
        )

        # Act
        fill1 = TestStubs.event_order_filled(
            order1,
            fill_price=Price("10000.00"),
            base_currency=BTC,
            quote_currency=USDT,
        )
        position = Position(fill1)

        fill2 = TestStubs.event_order_filled(
            order2,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("9999.00"),
            base_currency=BTC,
            quote_currency=USDT,
        )
        position.apply(fill2)
        self.assertEqual(Quantity(29), position.quantity)
        self.assertEqual(Money(0, BTC), position.realized_pnl)
        self.assertEqual(9999.413793103447, position.avg_open_price)

        fill3 = TestStubs.event_order_filled(
            order3,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("10001.00"),
            base_currency=BTC,
            quote_currency=USDT,
        )

        position.apply(fill3)
        self.assertEqual(Quantity(20), position.quantity)
        self.assertEqual(Money(0.00142767, BTC), position.realized_pnl)
        self.assertEqual(9999.413793103447, position.avg_open_price)

        fill4 = TestStubs.event_order_filled(
            order4,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("10003.00"),
            base_currency=BTC,
            quote_currency=USDT,
        )
        position.apply(fill4)
        self.assertEqual(Quantity(23), position.quantity)
        self.assertEqual(Money(0.00142767, BTC), position.realized_pnl)
        self.assertEqual(9999.88155922039, position.avg_open_price)

        fill5 = TestStubs.event_order_filled(
            order5,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("10005"),
            base_currency=BTC,
            quote_currency=USDT,
        )

        position.apply(fill5)
        self.assertEqual(Quantity(19), position.quantity)
        self.assertEqual(Money(0.00347507, BTC), position.realized_pnl)
        self.assertEqual(9999.88155922039, position.avg_open_price)
    def test_position_filled_with_buy_order_then_sell_order_returns_expected_attributes(self):
        # Arrange
        order = self.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000))

        fill1 = TestStubs.event_order_filled(
            order,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("1.00001"),
        )

        position = Position(fill1)

        fill2 = OrderFilled(
            self.account_id,
            order.cl_ord_id,
            OrderId("2"),
            ExecutionId("E2"),
            PositionId("T123456"),
            StrategyId("S", "001"),
            order.symbol,
            OrderSide.SELL,
            order.quantity,
            Quantity(),
            Price("1.00001"),
            Money(0, USD),
            LiquiditySide.TAKER,
            AUD,
            USD,
            UNIX_EPOCH + timedelta(minutes=1),
            uuid4(),
            UNIX_EPOCH,
        )

        last = QuoteTick(
            AUDUSD_FXCM,
            Price("1.00050"),
            Price("1.00048"),
            Quantity(1),
            Quantity(1),
            UNIX_EPOCH,
        )

        # Act
        position.apply(fill2)

        # Assert
        self.assertEqual(Quantity(), position.quantity)
        self.assertEqual(PositionSide.FLAT, position.side)
        self.assertEqual(UNIX_EPOCH, position.opened_time)
        self.assertEqual(timedelta(minutes=1), position.open_duration)
        self.assertEqual(1.00001, position.avg_open_price)
        self.assertEqual(2, position.event_count())
        self.assertEqual(datetime(1970, 1, 1, 0, 1, tzinfo=pytz.utc), position.closed_time)
        self.assertEqual(1.00001, position.avg_close_price)
        self.assertFalse(position.is_long())
        self.assertFalse(position.is_short())
        self.assertTrue(position.is_closed())
        self.assertEqual(0.0, position.realized_points)
        self.assertEqual(0.0, position.realized_return)
        self.assertEqual(Money(0, USD), position.realized_pnl)
        self.assertEqual(Money(0, USD), position.unrealized_pnl(last))
        self.assertEqual(Money(0, USD), position.total_pnl(last))
    def test_pnl_calculation_from_trading_technologies_example(self):
        # https://www.tradingtechnologies.com/xtrader-help/fix-adapter-reference/pl-calculation-algorithm/understanding-pl-calculations/  # noqa

        # Arrange
        order1 = self.order_factory.market(
            ETHUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity(12),
        )

        order2 = self.order_factory.market(
            ETHUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity(17),
        )

        order3 = self.order_factory.market(
            ETHUSDT_BINANCE.symbol,
            OrderSide.SELL,
            Quantity(9),
        )

        order4 = self.order_factory.market(
            ETHUSDT_BINANCE.symbol,
            OrderSide.SELL,
            Quantity(4),
        )

        order5 = self.order_factory.market(
            ETHUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity(3),
        )

        # Act
        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            fill_price=Price(100),
        )

        position = Position(fill1)

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            fill_price=Price(99),
        )

        position.apply(fill2)
        self.assertEqual(Quantity(29), position.quantity)
        self.assertEqual(Money("-2.88300000", USDT), position.realized_pnl)
        self.assertEqual(Decimal("99.41379310344827586206896552"), position.avg_open)

        fill3 = TestStubs.event_order_filled(
            order3,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price(101),
        )

        position.apply(fill3)
        self.assertEqual(Quantity(20), position.quantity)
        self.assertEqual(Money("10.48386207", USDT), position.realized_pnl)
        self.assertEqual(Decimal("99.41379310344827586206896552"), position.avg_open)

        fill4 = TestStubs.event_order_filled(
            order4,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price(105),
        )

        position.apply(fill4)
        self.assertEqual(Quantity(16), position.quantity)
        self.assertEqual(Money("32.40868966", USDT), position.realized_pnl)
        self.assertEqual(Decimal("99.41379310344827586206896552"), position.avg_open)

        fill5 = TestStubs.event_order_filled(
            order5,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price(103),
        )

        position.apply(fill5)
        self.assertEqual(Quantity(19), position.quantity)
        self.assertEqual(Money("32.09968966", USDT), position.realized_pnl)
        self.assertEqual(Decimal("99.98003629764065335753176042"), position.avg_open)
        self.assertEqual("Position(id=P-19700101-000000-000-001-1, LONG 19 ETH/USDT.BINANCE)", repr(position))
    def test_update_position_for_closed_position(self):
        # Arrange
        self.database.add_instrument(AUDUSD_SIM)

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

        position_id = PositionId("P-1")
        self.database.add_order(order1)

        order1.apply(TestStubs.event_order_submitted(order1))
        self.database.update_order(order1)

        order1.apply(TestStubs.event_order_accepted(order1))
        self.database.update_order(order1)

        order1.apply(
            TestStubs.event_order_filled(
                order1,
                instrument=AUDUSD_SIM,
                position_id=position_id,
                last_px=Price.from_str("1.00001"),
            ))
        self.database.update_order(order1)

        # Act
        position = Position(instrument=AUDUSD_SIM, fill=order1.last_event)
        self.database.add_position(position)

        order2 = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
        )

        self.database.add_order(order2)

        order2.apply(TestStubs.event_order_submitted(order2))
        self.database.update_order(order2)

        order2.apply(TestStubs.event_order_accepted(order2))
        self.database.update_order(order2)

        filled = TestStubs.event_order_filled(
            order2,
            instrument=AUDUSD_SIM,
            position_id=position_id,
            last_px=Price.from_str("1.00001"),
        )

        order2.apply(filled)
        self.database.update_order(order2)

        position.apply(filled)

        # Act
        self.database.update_position(position)

        # Assert
        assert self.database.load_position(position.id) == position
Example #29
0
    def test_several_positions_with_different_instruments_updates_portfolio(
            self):
        # Arrange
        state = AccountState(
            account_id=AccountId("SIM", "01234"),
            account_type=AccountType.MARGIN,
            base_currency=USD,
            reported=True,
            balances=[
                AccountBalance(
                    USD,
                    Money(1_000_000, USD),
                    Money(0, USD),
                    Money(1_000_000, USD),
                ),
            ],
            info={},
            event_id=uuid4(),
            updated_ns=0,
            timestamp_ns=0,
        )

        self.exec_engine.process(state)

        order1 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        order2 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        order3 = self.order_factory.market(
            GBPUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        order4 = self.order_factory.market(
            GBPUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
        )

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

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

        fill3 = TestStubs.event_order_filled(
            order3,
            instrument=GBPUSD_SIM,
            position_id=PositionId("P-3"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("1.00000"),
        )

        fill4 = TestStubs.event_order_filled(
            order4,
            instrument=GBPUSD_SIM,
            position_id=PositionId("P-3"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("1.00100"),
        )

        position1 = Position(instrument=AUDUSD_SIM, fill=fill1)
        position2 = Position(instrument=AUDUSD_SIM, fill=fill2)
        position3 = Position(instrument=GBPUSD_SIM, fill=fill3)

        last_audusd = QuoteTick(
            AUDUSD_SIM.id,
            Price.from_str("0.80501"),
            Price.from_str("0.80505"),
            Quantity.from_int(1),
            Quantity.from_int(1),
            0,
            0,
        )

        last_gbpusd = QuoteTick(
            GBPUSD_SIM.id,
            Price.from_str("1.30315"),
            Price.from_str("1.30317"),
            Quantity.from_int(1),
            Quantity.from_int(1),
            0,
            0,
        )

        self.cache.add_quote_tick(last_audusd)
        self.cache.add_quote_tick(last_gbpusd)
        self.portfolio.update_tick(last_audusd)
        self.portfolio.update_tick(last_gbpusd)

        self.cache.add_position(position1)
        self.cache.add_position(position2)
        self.cache.add_position(position3)

        # Act
        self.portfolio.update_position(
            TestStubs.event_position_opened(position1))
        self.portfolio.update_position(
            TestStubs.event_position_opened(position2))
        self.portfolio.update_position(
            TestStubs.event_position_opened(position3))

        position3.apply(fill4)
        self.cache.update_position(position3)
        self.portfolio.update_position(
            TestStubs.event_position_closed(position3))

        # Assert
        self.assertEqual(
            {USD: Money(-38998.00, USD)},
            self.portfolio.unrealized_pnls(SIM),
        )
        self.assertEqual(
            {USD: Money(161002.00, USD)},
            self.portfolio.net_exposures(SIM),
        )
        self.assertEqual({USD: Money(3912.06, USD)},
                         self.portfolio.maint_margins(SIM)),
        self.assertEqual(
            Money(161002.00, USD),
            self.portfolio.net_exposure(AUDUSD_SIM.id),
        )
        self.assertEqual(
            Money(-38998.00, USD),
            self.portfolio.unrealized_pnl(AUDUSD_SIM.id),
        )
        self.assertEqual(Money(0, USD),
                         self.portfolio.unrealized_pnl(GBPUSD_SIM.id))
        self.assertEqual(Decimal(200000),
                         self.portfolio.net_position(AUDUSD_SIM.id))
        self.assertEqual(Decimal(0),
                         self.portfolio.net_position(GBPUSD_SIM.id))
        self.assertTrue(self.portfolio.is_net_long(AUDUSD_SIM.id))
        self.assertTrue(self.portfolio.is_flat(GBPUSD_SIM.id))
        self.assertFalse(self.portfolio.is_completely_flat())
    def test_position_realised_pnl_with_interleaved_order_sides(self):
        # Arrange
        order1 = self.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity("12.000000"),
        )

        order2 = self.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity("17.000000"),
        )

        order3 = self.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.SELL,
            Quantity("9.000000"),
        )

        order4 = self.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity("3.000000"),
        )

        order5 = self.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.SELL,
            Quantity("4.000000"),
        )

        # Act
        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            fill_price=Price("10000.00"),
        )

        position = Position(fill1)

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            fill_price=Price("9999.00"),
        )

        position.apply(fill2)
        self.assertEqual(Quantity("29.000000"), position.quantity)
        self.assertEqual(Money("-289.98300000", USDT), position.realized_pnl)
        self.assertEqual(Decimal("9999.413793103448275862068966"), position.avg_open)

        fill3 = TestStubs.event_order_filled(
            order3,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("10001.00"),
        )

        position.apply(fill3)
        self.assertEqual(Quantity(20), position.quantity)
        self.assertEqual(Money("-365.71613793", USDT), position.realized_pnl)
        self.assertEqual(Decimal("9999.413793103448275862068966"), position.avg_open)

        fill4 = TestStubs.event_order_filled(
            order4,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("10003.00"),
        )

        position.apply(fill4)
        self.assertEqual(Quantity(23), position.quantity)
        self.assertEqual(Money("-395.72513793", USDT), position.realized_pnl)
        self.assertEqual(Decimal("9999.881559220389805097451274"), position.avg_open)

        fill5 = TestStubs.event_order_filled(
            order5,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-19700101-000000-000-001-1"),
            strategy_id=StrategyId("S", "001"),
            fill_price=Price("10005"),
        )

        position.apply(fill5)
        self.assertEqual(Quantity(19), position.quantity)
        self.assertEqual(Money("-415.27137481", USDT), position.realized_pnl)
        self.assertEqual(Decimal("9999.881559220389805097451274"), position.avg_open)
        self.assertEqual("Position(id=P-19700101-000000-000-001-1, LONG 19.000000 BTC/USDT.BINANCE)", repr(position))