def test_can_close_position_on_order_fill(self):
        # Arrange
        strategy = TradingStrategy(order_id_tag='001')
        strategy.change_clock(self.clock)

        self.exec_engine.register_strategy(strategy)

        position_id = strategy.position_id_generator.generate()

        order1 = strategy.order_factory.stop(AUDUSD_FXCM, OrderSide.BUY,
                                             Quantity(100000),
                                             Price(1.00000, 5))

        order2 = strategy.order_factory.stop(AUDUSD_FXCM, OrderSide.SELL,
                                             Quantity(100000),
                                             Price(1.00000, 5))

        submit_order1 = SubmitOrder(self.trader_id, self.account_id,
                                    strategy.id, position_id, order1,
                                    self.guid_factory.generate(),
                                    self.clock.time_now())

        submit_order2 = SubmitOrder(self.trader_id, self.account_id,
                                    strategy.id, position_id, order2,
                                    self.guid_factory.generate(),
                                    self.clock.time_now())

        self.exec_engine.execute_command(submit_order1)
        self.exec_engine.execute_command(submit_order2)

        order1_filled = TestStubs.event_order_filled(order1)
        order2_filled = TestStubs.event_order_filled(order2)

        # Act
        self.exec_engine.handle_event(order1_filled)
        self.exec_engine.handle_event(order2_filled)

        # # Assert
        self.assertTrue(self.exec_db.position_exists(position_id))
        self.assertFalse(self.exec_db.is_position_open(position_id))
        self.assertTrue(self.exec_db.is_position_closed(position_id))
        self.assertTrue(self.exec_engine.is_strategy_flat(strategy.id))
        self.assertTrue(self.exec_engine.is_flat())
        self.assertEqual(position_id,
                         self.exec_db.get_position(position_id).id)
        self.assertTrue(position_id in self.exec_db.get_positions(strategy.id))
        self.assertTrue(position_id in self.exec_db.get_positions())
        self.assertEqual(0, len(self.exec_db.get_positions_open(strategy.id)))
        self.assertEqual(0, len(self.exec_db.get_positions_open()))
        self.assertTrue(
            position_id in self.exec_db.get_positions_closed(strategy.id))
        self.assertTrue(position_id in self.exec_db.get_positions_closed())
        self.assertTrue(
            position_id not in self.exec_db.get_positions_open(strategy.id))
        self.assertTrue(position_id not in self.exec_db.get_positions_open())
        self.assertEqual(1, self.exec_db.count_positions_total())
        self.assertEqual(0, self.exec_db.count_positions_open())
        self.assertEqual(1, self.exec_db.count_positions_closed())
Пример #2
0
    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_can_handle_order_fill_event(self):
        # Arrange
        strategy = TradingStrategy(order_id_tag='001')
        strategy.change_clock(self.clock)

        self.exec_engine.register_strategy(strategy)

        position_id = strategy.position_id_generator.generate()
        order = strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                              Quantity(100000))

        submit_order = SubmitOrder(self.trader_id, self.account_id,
                                   strategy.id, position_id, order,
                                   self.guid_factory.generate(),
                                   self.clock.time_now())

        self.exec_engine.execute_command(submit_order)

        order_filled = TestStubs.event_order_filled(order)

        # Act
        self.exec_engine.handle_event(order_filled)

        # Assert
        self.assertTrue(self.exec_db.position_exists(position_id))
        self.assertTrue(self.exec_db.is_position_open(position_id))
        self.assertFalse(self.exec_db.is_position_closed(position_id))
        self.assertFalse(self.exec_engine.is_strategy_flat(strategy.id))
        self.assertFalse(self.exec_engine.is_flat())
        self.assertEqual(Position,
                         type(self.exec_db.get_position(position_id)))
        self.assertTrue(position_id in self.exec_db.get_positions())
        self.assertTrue(
            position_id not in self.exec_db.get_positions_closed(strategy.id))
        self.assertTrue(position_id not in self.exec_db.get_positions_closed())
        self.assertTrue(
            position_id in self.exec_db.get_positions_open(strategy.id))
        self.assertTrue(position_id in self.exec_db.get_positions_open())
        self.assertEqual(1, self.exec_db.count_positions_total())
        self.assertEqual(1, self.exec_db.count_positions_open())
        self.assertEqual(0, self.exec_db.count_positions_closed())
        self.assertTrue(self.exec_db.position_exists_for_order(order.id))
        self.assertEqual(Position,
                         type(self.exec_db.get_position_for_order(order.id)))
    def test_can_submit_order(self):
        # Arrange
        strategy = TradingStrategy(order_id_tag='001')
        strategy.change_clock(self.clock)

        self.exec_engine.register_strategy(strategy)

        position_id = strategy.position_id_generator.generate()
        order = strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                              Quantity(100000))

        submit_order = SubmitOrder(self.trader_id, self.account_id,
                                   strategy.id, position_id, order,
                                   self.guid_factory.generate(),
                                   self.clock.time_now())

        # Act
        self.exec_engine.execute_command(submit_order)

        # Assert
        self.assertIn(submit_order, self.exec_client.received_commands)
        self.assertTrue(self.exec_db.order_exists(order.id))
        self.assertEqual(position_id, self.exec_db.get_position_id(order.id))
class InMemoryExecutionDatabaseTests(unittest.TestCase):
    def setUp(self):
        # Fixture Setup
        clock = TestClock()
        logger = TestLogger()

        self.trader_id = TraderId('TESTER', '000')
        self.account_id = TestStubs.account_id()

        self.strategy = TradingStrategy(order_id_tag='001')
        self.strategy.change_clock(clock)
        self.strategy.change_logger(logger)

        self.database = InMemoryExecutionDatabase(trader_id=self.trader_id,
                                                  logger=logger)

    def test_can_add_order(self):
        # Arrange
        order = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                   Quantity(100000))
        position_id = self.strategy.position_id_generator.generate()

        # Act
        self.database.add_order(order, self.strategy.id, position_id)

        # Assert
        self.assertTrue(order.id in self.database.get_order_ids())
        self.assertEqual(order, self.database.get_orders()[order.id])

    def test_can_add_position(self):
        # Arrange
        order = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                   Quantity(100000))
        position_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order, self.strategy.id, position_id)

        order_filled = TestStubs.event_order_filled(order,
                                                    fill_price=Price(
                                                        1.00000, 5))
        position = Position(position_id, order_filled)

        # Act
        self.database.add_position(position, self.strategy.id)

        # Assert
        self.assertTrue(self.database.position_exists_for_order(order.id))
        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_open(self.strategy.id))
        self.assertTrue(position.id in self.database.get_positions_open())
        self.assertTrue(position.id not in self.database.get_positions_closed(
            self.strategy.id))
        self.assertTrue(
            position.id not in self.database.get_positions_closed())

    def test_can_update_order_for_working_order(self):
        # Arrange
        order = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                   Quantity(100000))
        position_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order, self.strategy.id, position_id)

        order_working = TestStubs.event_order_working(order)
        order.apply(order_working)

        # Act
        self.database.update_order(order)

        # Assert
        self.assertTrue(self.database.order_exists(order.id))
        self.assertTrue(order.id in self.database.get_order_ids())
        self.assertTrue(order.id in self.database.get_orders())
        self.assertTrue(
            order.id in self.database.get_orders_working(self.strategy.id))
        self.assertTrue(order.id in self.database.get_orders_working())
        self.assertTrue(order.id not in self.database.get_orders_completed(
            self.strategy.id))
        self.assertTrue(order.id not in self.database.get_orders_completed())

    def test_can_update_order_for_completed_order(self):
        # Arrange
        order = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                   Quantity(100000))
        position_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order, self.strategy.id, position_id)

        order_filled = TestStubs.event_order_filled(order,
                                                    fill_price=Price(
                                                        1.00001, 5))
        order.apply(order_filled)

        # Act
        self.database.update_order(order)

        # Assert
        self.assertTrue(self.database.order_exists(order.id))
        self.assertTrue(order.id in self.database.get_order_ids())
        self.assertTrue(order.id in self.database.get_orders())
        self.assertTrue(
            order.id in self.database.get_orders_completed(self.strategy.id))
        self.assertTrue(order.id in self.database.get_orders_completed())
        self.assertTrue(
            order.id not in self.database.get_orders_working(self.strategy.id))
        self.assertTrue(order.id not in self.database.get_orders_working())

    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_can_add_account(self):
        # Arrange
        event = AccountStateEvent(
            AccountId.py_from_string('SIMULATED-123456-SIMULATED'),
            Currency.USD, Money(1000000, Currency.USD),
            Money(1000000, Currency.USD), Money(0, Currency.USD),
            Money(0, Currency.USD), Money(0, Currency.USD), Decimal(0),
            ValidString('N'), GUID(uuid.uuid4()), UNIX_EPOCH)

        account = Account(event)

        # Act
        self.database.add_account(account)

        # Assert
        self.assertTrue(True)  # Did not raise exception

    def test_can_update_account(self):
        # Arrange
        event = AccountStateEvent(
            AccountId.py_from_string('SIMULATED-123456-SIMULATED'),
            Currency.USD, Money(1000000, Currency.USD),
            Money(1000000, Currency.USD), Money(0, Currency.USD),
            Money(0, Currency.USD), Money(0, Currency.USD), Decimal(0),
            ValidString('N'), GUID(uuid.uuid4()), UNIX_EPOCH)

        account = Account(event)
        self.database.add_account(account)

        # Act
        self.database.update_account(account)

        # Assert
        self.assertTrue(True)  # Did not raise exception

    def test_can_delete_strategy(self):
        # Arrange
        self.database.update_strategy(self.strategy)

        # Act
        self.database.delete_strategy(self.strategy)

        # Assert
        self.assertTrue(
            self.strategy.id not in self.database.get_strategy_ids())

    def test_can_check_residuals(self):
        # Arrange
        order1 = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                    Quantity(100000))
        position1_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order1, self.strategy.id, position1_id)

        order1_filled = TestStubs.event_order_filled(order1,
                                                     fill_price=Price(
                                                         1.00000, 5))
        position1 = Position(position1_id, order1_filled)
        self.database.update_order(order1)
        self.database.add_position(position1, self.strategy.id)

        order2 = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                    Quantity(100000))
        position2_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order2, self.strategy.id, position2_id)
        order2_working = TestStubs.event_order_working(order2)
        order2.apply(order2_working)

        self.database.update_order(order2)

        # Act
        self.database.check_residuals()

        # Does not raise exception

    def test_can_reset(self):
        # Arrange
        order1 = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                    Quantity(100000))
        position1_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order1, self.strategy.id, position1_id)

        order1_filled = TestStubs.event_order_filled(order1,
                                                     fill_price=Price(
                                                         1.00000, 5))
        position1 = Position(position1_id, order1_filled)
        self.database.update_order(order1)
        self.database.add_position(position1, self.strategy.id)

        order2 = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                    Quantity(100000))
        position2_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order2, self.strategy.id, position2_id)
        order2_working = TestStubs.event_order_working(order2)
        order2.apply(order2_working)

        self.database.update_order(order2)

        # Act
        self.database.reset()

        # Assert
        self.assertEqual(0, len(self.database.get_strategy_ids()))
        self.assertEqual(0, self.database.count_orders_total())
        self.assertEqual(0, self.database.count_positions_total())

    def test_can_flush(self):
        # Arrange
        order1 = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                    Quantity(100000))
        position1_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order1, self.strategy.id, position1_id)

        order1_filled = TestStubs.event_order_filled(order1,
                                                     fill_price=Price(
                                                         1.00000, 5))
        position1 = Position(position1_id, order1_filled)
        self.database.update_order(order1)
        self.database.add_position(position1, self.strategy.id)

        order2 = self.strategy.order_factory.market(AUDUSD_FXCM, OrderSide.BUY,
                                                    Quantity(100000))
        position2_id = self.strategy.position_id_generator.generate()
        self.database.add_order(order2, self.strategy.id, position2_id)
        order2_working = TestStubs.event_order_working(order2)
        order2.apply(order2_working)

        self.database.update_order(order2)

        # Act
        self.database.reset()
        self.database.flush()

        # Assert
        # Does not raise exception

    def test_get_strategy_ids_with_no_ids_returns_empty_set(self):
        # Arrange
        # Act
        result = self.database.get_strategy_ids()

        # Assert
        self.assertEqual(set(), result)

    def test_get_strategy_ids_with_id_returns_correct_set(self):
        # Arrange
        self.database.update_strategy(self.strategy)

        # Act
        result = self.database.get_strategy_ids()

        # Assert
        self.assertEqual({self.strategy.id}, result)

    def test_position_exists_when_no_position_returns_false(self):
        # Arrange
        # Act
        # Assert
        self.assertFalse(self.database.position_exists(PositionId('P-123456')))

    def test_order_exists_when_no_order_returns_false(self):
        # Arrange
        # Act
        # Assert
        self.assertFalse(self.database.order_exists(OrderId('O-123456')))

    def test_position_for_order_when_not_found_returns_none(self):
        # Arrange
        # Act
        # Assert
        self.assertIsNone(
            self.database.get_position_for_order(OrderId('O-123456')))

    def test_position_indexed_for_order_when_no_indexing_returns_false(self):
        # Arrange
        # Act
        # Assert
        self.assertFalse(
            self.database.position_indexed_for_order(OrderId('O-123456')))

    def test_get_order_when_no_order_returns_none(self):
        # Arrange
        position_id = PositionId('P-123456')

        # Act
        result = self.database.get_position(position_id)

        # Assert
        self.assertIsNone(result)

    def test_get_position_when_no_position_returns_none(self):
        # Arrange
        order_id = OrderId('O-201908080101-000-001')

        # Act
        result = self.database.get_order(order_id)

        # Assert
        self.assertIsNone(result)