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))
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"
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 )
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))
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"
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)]
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()))
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
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) ]
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'])
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))
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
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))