def test_position_filled_with_sell_order_returns_expected_attributes(self): # Arrange order = self.order_factory.market( AUDUSD_FXCM, OrderSide.SELL, Quantity(100000)) fill = TestStubs.event_order_filled( order, PositionId("P-123456"), StrategyId("S", "001"), Price("1.00001"), ) last = QuoteTick( AUDUSD_FXCM, Price("1.00050"), Price("1.00048"), Quantity(1), Quantity(1), UNIX_EPOCH, ) # Act position = Position(fill) # Assert self.assertEqual(Quantity(100000), position.quantity) self.assertEqual(Quantity(100000), position.peak_quantity) self.assertEqual(PositionSide.SHORT, position.side) self.assertEqual(UNIX_EPOCH, position.opened_time) self.assertEqual(1.00001, position.avg_open_price) self.assertEqual(1, position.event_count()) self.assertEqual({ExecutionId("E-19700101-000000-001-001-1")}, position.execution_ids()) self.assertEqual(ExecutionId("E-19700101-000000-001-001-1"), position.last_execution_id()) self.assertEqual(PositionId("P-123456"), position.id) 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(-47.00, USD), position.unrealized_pnl(last)) self.assertEqual(Money(-47.00, USD), position.total_pnl(last))
def test_apply_partial_fill_events_to_market_order_results_in_partially_filled( self, ): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) 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.from_str("1.00001"), last_qty=Quantity.from_int(20000), ) 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.from_str("1.00002"), last_qty=Quantity.from_int(40000), ) # Act order.apply(fill1) order.apply(fill2) # Assert self.assertEqual(OrderState.PARTIALLY_FILLED, order.state) self.assertEqual(Quantity.from_int(60000), order.filled_qty) self.assertEqual(Decimal("1.000014"), order.avg_px) self.assertEqual(2, len(order.execution_ids)) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) self.assertEqual(0, order.execution_ns)
def test_apply_partial_fill_events_to_market_order_results_in_partially_filled( self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) fill1 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00001"), fill_qty=Quantity(20000), ) fill2 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00002"), fill_qty=Quantity(40000), ) order.apply(submitted) order.apply(accepted) # Act order.apply(fill1) order.apply(fill2) # Assert self.assertEqual(OrderState.PARTIALLY_FILLED, order.state) self.assertEqual(Quantity(60000), order.filled_qty) self.assertEqual(Decimal("1.000014"), order.avg_price) self.assertEqual(2, len(order.execution_ids)) self.assertFalse(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp)
def test_update_order_for_closed_order(self): # Arrange order = self.strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) position_id = PositionId("P-1") self.cache.add_order(order, position_id) order.apply(TestEventStubs.order_submitted(order)) self.cache.update_order(order) order.apply(TestEventStubs.order_accepted(order)) self.cache.update_order(order) fill = TestEventStubs.order_filled(order, instrument=AUDUSD_SIM, last_px=Price.from_str("1.00001")) order.apply(fill) # Act self.cache.update_order(order) # Assert assert self.cache.order_exists(order.client_order_id) assert order.client_order_id in self.cache.client_order_ids() assert order in self.cache.orders() assert order not in self.cache.orders_open() assert order not in self.cache.orders_open( instrument_id=order.instrument_id) assert order not in self.cache.orders_open( strategy_id=self.strategy.id) assert order not in self.cache.orders_open( instrument_id=order.instrument_id, strategy_id=self.strategy.id) assert order in self.cache.orders_closed() assert order in self.cache.orders_closed( instrument_id=order.instrument_id) assert order in self.cache.orders_closed(strategy_id=self.strategy.id) assert order in self.cache.orders_closed( instrument_id=order.instrument_id, strategy_id=self.strategy.id) assert order not in self.cache.orders_inflight() assert order not in self.cache.orders_inflight( instrument_id=order.instrument_id) assert order not in self.cache.orders_inflight( strategy_id=self.strategy.id) assert order not in self.cache.orders_inflight( instrument_id=order.instrument_id, strategy_id=self.strategy.id) assert self.cache.venue_order_id( order.client_order_id) == order.venue_order_id assert self.cache.orders_open_count() == 0 assert self.cache.orders_closed_count() == 1 assert self.cache.orders_inflight_count() == 0 assert self.cache.orders_total_count() == 1
def test_update_order_for_completed_order(self): # Arrange order = self.strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) position_id = PositionId("P-1") self.cache.add_order(order, position_id) order.apply(TestStubs.event_order_submitted(order)) self.cache.update_order(order) order.apply(TestStubs.event_order_accepted(order)) self.cache.update_order(order) fill = TestStubs.event_order_filled(order, instrument=AUDUSD_SIM, last_px=Price.from_str("1.00001")) order.apply(fill) # Act self.cache.update_order(order) # Assert self.assertTrue(self.cache.order_exists(order.client_order_id)) self.assertIn(order.client_order_id, self.cache.client_order_ids()) self.assertIn(order, self.cache.orders()) self.assertIn(order, self.cache.orders_completed()) self.assertIn( order, self.cache.orders_completed(instrument_id=order.instrument_id)) self.assertIn( order, self.cache.orders_completed(strategy_id=self.strategy.id)) self.assertIn( order, self.cache.orders_completed(instrument_id=order.instrument_id, strategy_id=self.strategy.id), ) self.assertNotIn(order, self.cache.orders_working()) self.assertNotIn( order, self.cache.orders_working(instrument_id=order.instrument_id)) self.assertNotIn( order, self.cache.orders_working(strategy_id=self.strategy.id)) self.assertNotIn( order, self.cache.orders_working(instrument_id=order.instrument_id, strategy_id=self.strategy.id), ) self.assertEqual(order.venue_order_id, self.cache.venue_order_id(order.client_order_id)) self.assertEqual(0, self.cache.orders_working_count()) self.assertEqual(1, self.cache.orders_completed_count()) self.assertEqual(1, self.cache.orders_total_count())
def test_position_flipped_when_reduce_order_exceeds_original_quantity( self): # Arrange # Prepare market open_quote = QuoteTick( USDJPY_SIM.symbol, Price("90.002"), Price("90.003"), Quantity(1), Quantity(1), UNIX_EPOCH, ) self.data_engine.process(open_quote) self.exchange.process_tick(open_quote) order_open = self.strategy.order_factory.market( USDJPY_SIM.symbol, OrderSide.BUY, Quantity(100000), ) # Act 1 self.strategy.submit_order(order_open) reduce_quote = QuoteTick( USDJPY_SIM.symbol, Price("100.003"), Price("100.003"), Quantity(1), Quantity(1), UNIX_EPOCH, ) self.exchange.process_tick(reduce_quote) self.portfolio.update_tick(reduce_quote) order_reduce = self.strategy.order_factory.market( USDJPY_SIM.symbol, OrderSide.SELL, Quantity(150000), ) # Act 2 self.strategy.submit_order( order_reduce, PositionId("P-19700101-000000-000-001-1")) # Generated by platform # Assert print(self.exec_engine.cache.positions()) position_open = self.exec_engine.cache.positions_open()[0] position_closed = self.exec_engine.cache.positions_closed()[0] self.assertEqual(PositionSide.SHORT, position_open.side) self.assertEqual(Quantity(50000), position_open.quantity) self.assertEqual(Money(999619.98, JPY), position_closed.realized_pnl) self.assertEqual([Money(380.02, JPY)], position_closed.commissions())
def test_position_filled_with_sell_order_returns_expected_attributes(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) fill = TestEventStubs.order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), ) last = Price.from_str("1.00050") # Act position = Position(instrument=AUDUSD_SIM, fill=fill) # Assert assert position.quantity == Quantity.from_int(100000) assert position.peak_qty == Quantity.from_int(100000) assert position.side == PositionSide.SHORT assert position.ts_opened == 0 assert position.avg_px_open == Decimal("1.00001") assert position.event_count == 1 assert position.trade_ids == [TradeId("E-19700101-000000-000-001-1")] assert position.last_trade_id == TradeId("E-19700101-000000-000-001-1") assert position.id == PositionId("P-123456") 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(-2.00, USD) assert position.unrealized_pnl(last) == Money(-49.00, USD) assert position.total_pnl(last) == Money(-51.00, USD) assert position.commissions() == [Money(2.00, USD)] assert repr( position) == "Position(SHORT 100_000 AUD/USD.SIM, id=P-123456)"
def test_position_filled_with_sell_order_returns_expected_attributes(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(100000), ) fill = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00001"), ) last = Price("1.00050") # Act position = Position(fill) # Assert self.assertEqual(Quantity(100000), position.quantity) self.assertEqual(Quantity(100000), position.peak_quantity) self.assertEqual(PositionSide.SHORT, position.side) self.assertEqual(UNIX_EPOCH, position.opened_time) self.assertEqual(Decimal("1.00001"), position.avg_open) self.assertEqual(1, position.event_count) self.assertEqual([ExecutionId("E-19700101-000000-000-001-1")], position.execution_ids) self.assertEqual(ExecutionId("E-19700101-000000-000-001-1"), position.last_execution_id) self.assertEqual(PositionId("P-123456"), position.id) 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(-2.00, USD), position.realized_pnl) self.assertEqual(Money(-49.00, USD), position.unrealized_pnl(last)) self.assertEqual(Money(-51.00, USD), position.total_pnl(last)) self.assertEqual(Money(2.00, USD), position.commission) self.assertEqual([Money(2.00, USD)], position.commissions()) self.assertEqual("Position(id=P-123456, SHORT 100,000 AUD/USD.SIM)", repr(position))
def test_add_position(self): # Arrange order = self.strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) position_id = PositionId("P-1") self.cache.add_order(order, position_id) fill = TestEventStubs.order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-1"), last_px=Price.from_str("1.00000"), ) position = Position(instrument=AUDUSD_SIM, fill=fill) # Act self.cache.add_position(position, OMSType.HEDGING) # Assert assert self.cache.position_exists(position.id) assert position.id in self.cache.position_ids() assert position in self.cache.positions() assert position in self.cache.positions_open() assert position in self.cache.positions_open( instrument_id=position.instrument_id) assert position in self.cache.positions_open( strategy_id=self.strategy.id) assert position in self.cache.positions_open( instrument_id=position.instrument_id, strategy_id=self.strategy.id) assert position not in self.cache.positions_closed() assert position not in self.cache.positions_closed( instrument_id=position.instrument_id) assert position not in self.cache.positions_closed( strategy_id=self.strategy.id) assert position not in self.cache.positions_closed( instrument_id=position.instrument_id, strategy_id=self.strategy.id) assert self.cache.position_for_order(order.client_order_id) == position assert self.cache.orders_for_position(position.id) == [order]
def test_update_orders_working(self): # Arrange self.portfolio.register_account(self.account) # Create two working orders order1 = self.order_factory.stop_market( BTCUSDT_BINANCE.symbol, OrderSide.BUY, Quantity("10.5"), Price("25000.00"), ) order2 = self.order_factory.stop_market( BTCUSDT_BINANCE.symbol, OrderSide.BUY, Quantity("10.5"), Price("25000.00"), ) # Push state to WORKING order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) filled1 = TestStubs.event_order_filled( order1, instrument=BTCUSDT_BINANCE, position_id=PositionId("P-1"), strategy_id=StrategyId("S", "1"), fill_price=Price("25000.00"), ) # Push state to FILLED order1.apply(filled1) # Push state to WORKING order2.apply(TestStubs.event_order_submitted(order2)) order2.apply(TestStubs.event_order_accepted(order2)) order2.apply(TestStubs.event_order_working(order2)) # Update the last quote last = QuoteTick( BTCUSDT_BINANCE.symbol, Price("25001.00"), Price("25002.00"), Quantity(1), Quantity(1), UNIX_EPOCH, ) # Act self.portfolio.update_tick(last) self.portfolio.initialize_orders({order1, order2}) # Assert self.assertEqual({}, self.portfolio.initial_margins(BINANCE))
def test_update_order_for_accepted_order(self): # Arrange order = self.strategy.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) position_id = PositionId("P-1") self.cache.add_order(order, position_id) order.apply(TestStubs.event_order_submitted(order)) self.cache.update_order(order) order.apply(TestStubs.event_order_accepted(order)) # Act self.cache.update_order(order) # Assert assert self.cache.order_exists(order.client_order_id) assert order.client_order_id in self.cache.client_order_ids() assert order in self.cache.orders() assert order in self.cache.orders_active() assert order in self.cache.orders_active(instrument_id=order.instrument_id) assert order in self.cache.orders_active(strategy_id=self.strategy.id) assert order in self.cache.orders_active( instrument_id=order.instrument_id, strategy_id=self.strategy.id ) assert order not in self.cache.orders_inflight() assert order not in self.cache.orders_inflight() assert order not in self.cache.orders_inflight(instrument_id=order.instrument_id) assert order not in self.cache.orders_inflight(strategy_id=self.strategy.id) assert order not in self.cache.orders_inflight( instrument_id=order.instrument_id, strategy_id=self.strategy.id ) assert order in self.cache.orders_working() assert order in self.cache.orders_working(instrument_id=order.instrument_id) assert order in self.cache.orders_working(strategy_id=self.strategy.id) assert order in self.cache.orders_working( instrument_id=order.instrument_id, strategy_id=self.strategy.id ) assert order not in self.cache.orders_completed() assert order not in self.cache.orders_completed(instrument_id=order.instrument_id) assert order not in self.cache.orders_completed(strategy_id=self.strategy.id) assert order not in self.cache.orders_completed( instrument_id=order.instrument_id, strategy_id=self.strategy.id ) assert self.cache.orders_active_count() == 1 assert self.cache.orders_inflight_count() == 0 assert self.cache.orders_working_count() == 1 assert self.cache.orders_completed_count() == 0 assert self.cache.orders_total_count() == 1
def test_generate_order_fills_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(1500000), Price("0.80010"), ) order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) order1.apply(TestStubs.event_order_working(order1)) order2 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(1500000), Price("0.80000"), ) submitted2 = TestStubs.event_order_submitted(order2) accepted2 = TestStubs.event_order_accepted(order2) working2 = TestStubs.event_order_working(order2) order2.apply(submitted2) order2.apply(accepted2) order2.apply(working2) filled = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-1"), strategy_id=StrategyId("S", "1"), fill_price=Price("0.80011"), ) order1.apply(filled) orders = [order1, order2] # Act report = report_provider.generate_order_fills_report(orders) # Assert self.assertEqual(1, len(report)) self.assertEqual("cl_ord_id", report.index.name) self.assertEqual(order1.cl_ord_id.value, report.index[0]) self.assertEqual("AUD/USD", report.iloc[0]["symbol"]) self.assertEqual("BUY", report.iloc[0]["side"]) self.assertEqual("LIMIT", report.iloc[0]["type"]) self.assertEqual(1500000, report.iloc[0]["quantity"]) self.assertEqual(0.80011, report.iloc[0]["avg_price"]) self.assertEqual(0.00001, report.iloc[0]["slippage"])
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_pnls_for_multi_currency_cash_account_adabtc(self): # Arrange event = AccountState( account_id=AccountId("SIM", "001"), account_type=AccountType.CASH, base_currency=None, # Multi-currency reported=True, balances=[ AccountBalance( BTC, Money(1.00000000, BTC), Money(0.00000000, BTC), Money(1.00000000, BTC), ), AccountBalance( ADA, Money(1000.00000000, ADA), Money(0.00000000, ADA), Money(1000.00000000, ADA), ), ], info={}, # No default currency set event_id=UUID4(), ts_event=0, ts_init=0, ) account = CashAccount(event) order = self.order_factory.market( ADABTC_BINANCE.id, OrderSide.BUY, Quantity.from_int(100), ) fill = TestStubs.event_order_filled( order, instrument=ADABTC_BINANCE, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("0.00004100"), ) position = Position(ADABTC_BINANCE, fill) # Act result = account.calculate_pnls( instrument=ADABTC_BINANCE, position=position, fill=fill, ) # Assert assert result == [Money(100.000000, ADA), Money(-0.00410410, BTC)]
def on_bar(self, bar_type, bar): self.object_storer.store((bar_type, Bar)) if bar_type.equals(self.bar_type): if self.ema1.value > self.ema2.value: buy_order = self.order_factory.market(self.bar_type.symbol, Label('TestStrategy1_E'), OrderSide.BUY, 100000) self.submit_order(buy_order, PositionId(str(buy_order.id))) self.position_id = buy_order.id elif self.ema1.value < self.ema2.value: sell_order = self.order_factory.market( self.bar_type.symbol, Label('TestStrategy1_E'), OrderSide.SELL, 100000) self.submit_order(sell_order, PositionId(str(sell_order.id))) self.position_id = sell_order.id
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_update_order_for_accepted_order(self): # Arrange order = self.strategy.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) position_id = PositionId('P-1') self.cache.add_order(order, position_id) order.apply(TestStubs.event_order_submitted(order)) self.cache.update_order(order) order.apply(TestStubs.event_order_accepted(order)) # Act self.cache.update_order(order) # Assert self.assertTrue(self.cache.order_exists(order.cl_ord_id)) self.assertIn(order.cl_ord_id, self.cache.order_ids()) self.assertIn(order, self.cache.orders()) self.assertIn(order, self.cache.orders_active()) self.assertIn(order, self.cache.orders_active(symbol=order.symbol)) self.assertIn(order, self.cache.orders_active(strategy_id=self.strategy.id)) self.assertIn( order, self.cache.orders_active(symbol=order.symbol, strategy_id=self.strategy.id)) self.assertIn(order, self.cache.orders_working()) self.assertIn(order, self.cache.orders_working(symbol=order.symbol)) self.assertIn(order, self.cache.orders_working(strategy_id=self.strategy.id)) self.assertIn( order, self.cache.orders_working(symbol=order.symbol, strategy_id=self.strategy.id)) self.assertNotIn(order, self.cache.orders_completed()) self.assertNotIn(order, self.cache.orders_completed(symbol=order.symbol)) self.assertNotIn( order, self.cache.orders_completed(strategy_id=self.strategy.id)) self.assertNotIn( order, self.cache.orders_completed(symbol=order.symbol, strategy_id=self.strategy.id)) self.assertEqual(1, self.cache.orders_active_count()) self.assertEqual(1, self.cache.orders_working_count()) self.assertEqual(0, self.cache.orders_completed_count()) self.assertEqual(1, self.cache.orders_total_count())
def test_can_change_clock(self): # Arrange clock = TestClock() strategy = TradingStrategy(order_id_tag='001') # Act strategy.change_clock(clock) # Assert self.assertEqual(UNIX_EPOCH, strategy.time_now()) self.assertEqual(PositionId('P-19700101-000000-000-001-1'), strategy.position_id_generator.generate())
def test_position_partial_fills_with_buy_order_returns_expected_attributes(self): # Arrange order = self.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) order_partially_filled = OrderPartiallyFilled( self.account_id, order.id, ExecutionId('E123456'), PositionIdBroker('T123456'), order.symbol, order.side, Quantity(50000), Quantity(50000), Price(1.00001, 5), Currency.USD, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) last = Tick(AUDUSD_FXCM, Price(1.00050, 5), Price(1.00048, 5), Volume(1), Volume(1), UNIX_EPOCH) position = Position(PositionId('P-123456'), order_partially_filled) # Act # Assert self.assertEqual(Quantity(50000), position.quantity) self.assertEqual(Quantity(50000), position.peak_quantity) self.assertEqual(MarketPosition.LONG, position.market_position) self.assertEqual(UNIX_EPOCH, position.opened_time) self.assertEqual(1.00001, position.average_open_price) self.assertEqual(1, position.event_count) self.assertEqual(ExecutionId('E123456'), position.last_execution_id) self.assertEqual(PositionIdBroker('T123456'), position.id_broker) self.assertTrue(position.is_long) self.assertFalse(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, Currency.USD), position.realized_pnl) self.assertEqual(0.0004899999999998794, position.unrealized_points(last)) self.assertEqual(0.0004899951000488789, position.unrealized_return(last)) self.assertEqual(Money(24.50, Currency.USD), position.unrealized_pnl(last)) self.assertEqual(0.0004899999999998794, position.total_points(last)) self.assertEqual(0.0004899951000488789, position.total_return(last)) self.assertEqual(Money(24.50, Currency.USD), position.total_pnl(last))
def test_reset_id_generator(self): # Arrange self.position_id_generator.generate(StrategyId("S", "002")) self.position_id_generator.generate(StrategyId("S", "002")) self.position_id_generator.generate(StrategyId("S", "002")) # Act self.position_id_generator.reset() result1 = self.position_id_generator.generate(StrategyId("S", "002")) # Assert self.assertEqual(PositionId("P-19700101-000000-001-002-1"), result1)
def test_can_reset_id_generator(self): # Arrange self.position_id_generator.generate() self.position_id_generator.generate() self.position_id_generator.generate() # Act self.position_id_generator.reset() result1 = self.position_id_generator.generate() # Assert self.assertEqual(PositionId('P-19700101-000000-001-001-1'), result1)
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_handle_position_opening_with_position_id_none(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) self.exec_engine.execute(submit_order) # Act self.exec_engine.process(TestStubs.event_order_submitted(order)) self.exec_engine.process(TestStubs.event_order_accepted(order)) self.exec_engine.process(TestStubs.event_order_filled(order, AUDUSD_SIM, PositionId.null())) expected_id = PositionId("P-000-AUD/USD.SIM-1") # Generated inside engine # Assert self.assertTrue(self.cache.position_exists(expected_id)) self.assertTrue(self.cache.is_position_open(expected_id)) self.assertFalse(self.cache.is_position_closed(expected_id)) self.assertEqual(Position, type(self.cache.position(expected_id))) self.assertIn(expected_id, self.cache.position_ids()) self.assertNotIn(expected_id, self.cache.position_closed_ids(strategy_id=strategy.id)) self.assertNotIn(expected_id, self.cache.position_closed_ids()) self.assertIn(expected_id, self.cache.position_open_ids(strategy_id=strategy.id)) self.assertIn(expected_id, self.cache.position_open_ids()) self.assertEqual(1, self.cache.positions_total_count()) self.assertEqual(1, self.cache.positions_open_count()) self.assertEqual(0, self.cache.positions_closed_count())
def test_handle_position_opening_with_position_id_none(self): # Arrange strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), clock=self.clock, uuid_factory=TestUUIDFactory(), logger=self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder(self.venue, self.trader_id, self.account_id, strategy.id, PositionId.py_null(), order, self.uuid_factory.generate(), self.clock.utc_now()) self.exec_engine.execute(submit_order) # Act self.exec_engine.process(TestStubs.event_order_submitted(order)) self.exec_engine.process(TestStubs.event_order_accepted(order)) self.exec_engine.process(TestStubs.event_order_filled(order)) expected_id = PositionId( "O-19700101-000000-000-001-1") # Stubbed from order id # Assert self.assertTrue(self.cache.position_exists(expected_id)) self.assertTrue(self.cache.is_position_open(expected_id)) self.assertFalse(self.cache.is_position_closed(expected_id)) self.assertFalse( self.exec_engine.cache.is_flat(strategy_id=strategy.id)) self.assertFalse(self.exec_engine.cache.is_flat()) self.assertEqual(Position, type(self.cache.position(expected_id))) self.assertTrue(expected_id in self.cache.position_ids()) self.assertTrue(expected_id not in self.cache.position_closed_ids( strategy_id=strategy.id)) self.assertTrue(expected_id not in self.cache.position_closed_ids()) self.assertTrue(expected_id in self.cache.position_open_ids( strategy_id=strategy.id)) self.assertTrue(expected_id in self.cache.position_open_ids()) self.assertEqual(1, self.cache.positions_total_count()) self.assertEqual(1, self.cache.positions_open_count()) self.assertEqual(0, self.cache.positions_closed_count()) self.assertTrue(self.cache.position_exists_for_order(order.cl_ord_id))
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_reset_id_generator(self): # Arrange self.position_id_generator.generate(TestStubs.symbol_audusd_fxcm()) self.position_id_generator.generate(TestStubs.symbol_audusd_fxcm()) self.position_id_generator.generate(TestStubs.symbol_audusd_fxcm()) # Act self.position_id_generator.reset() result1 = self.position_id_generator.generate( TestStubs.symbol_audusd_fxcm()) # Assert self.assertEqual(PositionId("P-001-AUD/USD.SIM-1"), result1)
def test_market_value_when_insufficient_data_for_xrate_returns_none(self): # Arrange state = AccountState( account_id=AccountId("BITMEX", "01234"), balances=[Money("10.00000000", BTC), Money("10.00000000", ETH)], balances_free=[Money("10.00000000", BTC), Money("10.00000000", ETH)], balances_locked=[Money("0.00000000", BTC), Money("0.00000000", ETH)], info={}, event_id=uuid4(), event_timestamp=UNIX_EPOCH, ) account = Account(state) self.portfolio.register_account(account) order = self.order_factory.market( ETHUSD_BITMEX.symbol, OrderSide.BUY, Quantity(100), ) fill = TestStubs.event_order_filled( order=order, instrument=ETHUSD_BITMEX, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("376.05"), ) last_ethusd = QuoteTick( ETHUSD_BITMEX.symbol, Price("376.05"), Price("377.10"), Quantity("16"), Quantity("25"), UNIX_EPOCH, ) position = Position(fill) self.portfolio.update_position(TestStubs.event_position_opened(position)) self.data_cache.add_quote_tick(last_ethusd) self.portfolio.update_tick(last_ethusd) # Act result = self.portfolio.market_values(BITMEX) # Assert # TODO: Currently no Quanto thus no xrate required self.assertEqual({ETH: Money('0.02659221', ETH)}, result)
def test_opening_one_long_position_updates_portfolio(self): # Arrange order = self.order_factory.market( BTCUSDT_BINANCE.symbol, OrderSide.BUY, Quantity("10.000000"), ) fill = TestStubs.event_order_filled( order=order, instrument=BTCUSDT_BINANCE, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("10500.00"), ) last = QuoteTick( BTCUSDT_BINANCE.symbol, Price("10510.00"), Price("10511.00"), Quantity("1.000000"), Quantity("1.000000"), UNIX_EPOCH, ) self.data_cache.add_quote_tick(last) self.portfolio.update_tick(last) position = Position(fill) # Act self.portfolio.update_position( TestStubs.event_position_opened(position)) # Assert self.assertEqual({USDT: Money("105100.00000000", USDT)}, self.portfolio.market_values(BINANCE)) self.assertEqual({USDT: Money("100.00000000", USDT)}, self.portfolio.unrealized_pnls(BINANCE)) self.assertEqual({}, self.portfolio.maint_margins(BINANCE)) self.assertEqual(Money("105100.00000000", USDT), self.portfolio.market_value(BTCUSDT_BINANCE.symbol)) self.assertEqual(Money("100.00000000", USDT), self.portfolio.unrealized_pnl(BTCUSDT_BINANCE.symbol)) self.assertEqual(Decimal("10.00000000"), self.portfolio.net_position(order.symbol)) self.assertTrue(self.portfolio.is_net_long(order.symbol)) self.assertFalse(self.portfolio.is_net_short(order.symbol)) self.assertFalse(self.portfolio.is_flat(order.symbol)) self.assertFalse(self.portfolio.is_completely_flat())
def test_apply_order_partially_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) working = TestStubs.event_order_working(order) partially = OrderFilled( self.account_id, order.cl_ord_id, OrderId("1"), ExecutionId("E-1"), PositionId("P-1"), StrategyId.null(), order.symbol, order.side, Quantity(50000), Quantity(50000), Quantity(50000), Price("0.999999"), AUDUSD_SIM.quote_currency, AUDUSD_SIM.is_inverse, Money(0, USD), LiquiditySide.MAKER, UNIX_EPOCH, uuid4(), UNIX_EPOCH, ) order.apply(submitted) order.apply(accepted) order.apply(working) # Act order.apply(partially) # Assert self.assertEqual(OrderState.PARTIALLY_FILLED, order.state) self.assertEqual(Quantity(50000), order.filled_qty) self.assertEqual(Price("1.00000"), order.price) self.assertEqual(Decimal("0.999999"), order.avg_price) self.assertEqual(Decimal("-0.000001"), order.slippage) self.assertFalse(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp)
def test_load_order_when_order_in_database_returns_order(self): # Arrange order = self.strategy.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) position_id = PositionId('P-1') self.database.add_order(order, position_id) # Act result = self.database.load_order(order.cl_ord_id) # Assert self.assertEqual(order, result)