class RedisExecutionDatabaseTests(unittest.TestCase):
    def setUp(self):
        # Fixture Setup
        clock = TestClock()
        logger = TestLogger(clock)

        self.trader_id = TraderId("TESTER", "000")

        self.strategy = TradingStrategy(order_id_tag="001")
        self.strategy.register_trader(
            TraderId("TESTER", "000"),
            clock,
            logger,
        )

        config = {
            'host': 'localhost',
            'port': 6379,
        }

        self.database = RedisExecutionDatabase(
            trader_id=self.trader_id,
            logger=logger,
            command_serializer=MsgPackCommandSerializer(),
            event_serializer=MsgPackEventSerializer(),
            config=config,
        )

        self.test_redis = redis.Redis(host="localhost", port=6379, db=0)

    def tearDown(self):
        # Tests will start failing if redis is not flushed on tear down
        self.test_redis.flushall(
        )  # Comment this line out to preserve data between tests

    def test_add_account(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)

        # Act
        self.database.add_account(account)

        # Assert
        self.assertEqual(account, self.database.load_account(account.id))

    def test_add_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        # Act
        self.database.add_order(order)

        # Assert
        self.assertEqual(order, self.database.load_order(order.cl_ord_id))

    def test_add_position(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        self.database.add_order(order)

        position_id = PositionId('P-1')
        order_filled = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            position_id=position_id,
            fill_price=Price("1.00000"),
        )

        position = Position(order_filled)

        # Act
        self.database.add_position(position)

        # Assert
        self.assertEqual(position, self.database.load_position(position.id))

    def test_update_account(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)
        self.database.add_account(account)

        # Act
        self.database.update_account(account)

        # Assert
        self.assertEqual(account, self.database.load_account(account.id))

    def test_update_order_for_working_order(self):
        # Arrange
        order = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        self.database.add_order(order)

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

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

        # Act
        order.apply(TestStubs.event_order_working(order))
        self.database.update_order(order)

        # Assert
        self.assertEqual(order, self.database.load_order(order.cl_ord_id))

    def test_update_order_for_completed_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        self.database.add_order(order)

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

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

        order.apply(
            TestStubs.event_order_filled(
                order,
                instrument=AUDUSD_SIM,
                fill_price=Price("1.00001"),
            ))

        # Act
        self.database.update_order(order)

        # Assert
        self.assertEqual(order, self.database.load_order(order.cl_ord_id))

    def test_update_position_for_closed_position(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(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,
                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_SIM.symbol,
            OrderSide.SELL,
            Quantity(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,
            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_load_account_when_no_account_in_database_returns_none(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)

        # Act
        result = self.database.load_account(account.id)

        # Assert
        self.assertIsNone(result)

    def test_load_account_when_account_in_database_returns_account(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)
        self.database.add_account(account)

        # Act
        result = self.database.load_account(account.id)

        # Assert
        self.assertEqual(account, result)

    def test_load_order_when_no_order_in_database_returns_none(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        # Act
        result = self.database.load_order(order.cl_ord_id)

        # Assert
        self.assertIsNone(result)

    def test_load_order_when_market_order_in_database_returns_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        self.database.add_order(order)

        # Act
        result = self.database.load_order(order.cl_ord_id)

        # Assert
        self.assertEqual(order, result)

    def test_load_order_when_limit_order_in_database_returns_order(self):
        # Arrange
        order = self.strategy.order_factory.limit(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        self.database.add_order(order)

        # Act
        result = self.database.load_order(order.cl_ord_id)

        # Assert
        self.assertEqual(order, result)

    def test_load_order_when_stop_market_order_in_database_returns_order(self):
        # Arrange
        order = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        self.database.add_order(order)

        # Act
        result = self.database.load_order(order.cl_ord_id)

        # Assert
        self.assertEqual(order, result)

    def test_load_position_when_no_position_in_database_returns_none(self):
        # Arrange
        position_id = PositionId('P-1')

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

        # Assert
        self.assertIsNone(result)

    def test_load_order_when_position_in_database_returns_position(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        self.database.add_order(order)

        position_id = PositionId('P-1')
        order_filled = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            position_id=position_id,
            fill_price=Price("1.00000"),
        )

        position = Position(order_filled)

        self.database.add_position(position)

        # Act
        result = self.database.load_position(position_id)
        # Assert
        self.assertEqual(position, result)

    def test_load_accounts_when_no_accounts_returns_empty_dict(self):
        # Arrange
        # Act
        result = self.database.load_accounts()

        # Assert
        self.assertEqual({}, result)

    def test_load_accounts_cache_when_one_account_in_database(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)
        self.database.add_account(account)

        # Act
        # Assert
        self.assertEqual(account, self.database.load_account(account.id))

    def test_load_orders_cache_when_no_orders(self):
        # Arrange
        # Act
        self.database.load_orders()

        # Assert
        self.assertEqual({}, self.database.load_orders())

    def test_load_orders_cache_when_one_order_in_database(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        self.database.add_order(order)

        # Act
        result = self.database.load_orders()

        # Assert
        self.assertEqual({order.cl_ord_id: order}, result)

    def test_load_positions_cache_when_no_positions(self):
        # Arrange
        # Act
        self.database.load_positions()

        # Assert
        self.assertEqual({}, self.database.load_positions())

    def test_load_positions_cache_when_one_position_in_database(self):
        # Arrange
        order1 = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        self.database.add_order(order1)

        position_id = PositionId('P-1')
        order1.apply(TestStubs.event_order_submitted(order1))
        order1.apply(TestStubs.event_order_accepted(order1))
        order1.apply(TestStubs.event_order_working(order1))
        order1.apply(
            TestStubs.event_order_filled(
                order1,
                instrument=AUDUSD_SIM,
                position_id=position_id,
                fill_price=Price("1.00001"),
            ))

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

        # Act
        result = self.database.load_positions()

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

    def test_delete_strategy(self):
        # Arrange
        # Act
        self.database.delete_strategy(self.strategy.id)
        result = self.database.load_strategy(self.strategy.id)

        # Assert
        self.assertEqual({}, result)

    def test_flush(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        self.database.add_order(order1)

        position1_id = PositionId('P-1')
        filled = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=position1_id,
            fill_price=Price("1.00000"),
        )

        position1 = Position(filled)
        self.database.update_order(order1)
        self.database.add_position(position1)

        order2 = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        self.database.add_order(order2)

        order2.apply(TestStubs.event_order_submitted(order2))
        order2.apply(TestStubs.event_order_accepted(order2))
        order2.apply(TestStubs.event_order_working(order2))

        self.database.update_order(order2)

        # Act
        self.database.flush()

        # Assert
        self.assertIsNone(self.database.load_order(order1.cl_ord_id))
        self.assertIsNone(self.database.load_order(order2.cl_ord_id))
        self.assertIsNone(self.database.load_position(position1.id))
class LiveExecutionPerformanceTests(unittest.TestCase):
    def setUp(self):
        # Fixture Setup
        self.clock = LiveClock()
        self.uuid_factory = UUIDFactory()
        self.logger = TestLogger(self.clock, bypass_logging=True)

        self.trader_id = TraderId("TESTER", "000")
        self.account_id = AccountId("BINANCE", "001")

        self.portfolio = Portfolio(
            clock=self.clock,
            logger=self.logger,
        )
        self.portfolio.register_cache(DataCache(self.logger))

        self.analyzer = PerformanceAnalyzer()

        # Fresh isolated loop testing pattern
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)

        database = BypassExecutionDatabase(trader_id=self.trader_id,
                                           logger=self.logger)
        self.exec_engine = LiveExecutionEngine(
            loop=self.loop,
            database=database,
            portfolio=self.portfolio,
            clock=self.clock,
            logger=self.logger,
        )

        exec_client = MockExecutionClient(
            venue=Venue("BINANCE"),
            account_id=self.account_id,
            exec_engine=self.exec_engine,
            clock=self.clock,
            logger=self.logger,
        )

        self.exec_engine.register_client(exec_client)
        self.exec_engine.process(TestStubs.event_account_state(
            self.account_id))

        self.strategy = TradingStrategy(order_id_tag="001")
        self.strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(self.strategy)

    def submit_order(self):
        order = self.strategy.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity("1.00000000"),
        )

        self.strategy.submit_order(order)

    def test_execute_command(self):
        order = self.strategy.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity("1.00000000"),
        )

        command = SubmitOrder(
            order.symbol.venue,
            self.trader_id,
            self.account_id,
            self.strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        def execute_command():
            self.exec_engine.execute(command)

        PerformanceHarness.profile_function(execute_command, 10000, 1)
        # ~0.0ms / ~0.3μs / 253ns minimum of 10,000 runs @ 1 iteration each run.

    def test_submit_order(self):
        self.exec_engine.start()
        time.sleep(0.1)

        async def run_test():
            def submit_order():
                order = self.strategy.order_factory.market(
                    BTCUSDT_BINANCE.symbol,
                    OrderSide.BUY,
                    Quantity("1.00000000"),
                )

                self.strategy.submit_order(order)

            PerformanceHarness.profile_function(submit_order, 10000, 1)

        self.loop.run_until_complete(run_test())
        # ~0.0ms / ~32.3μs / 32260ns minimum of 10,000 runs @ 1 iteration each run.

    def test_submit_order_end_to_end(self):
        self.exec_engine.start()
        time.sleep(0.1)

        async def run_test():
            for _ in range(10000):
                order = self.strategy.order_factory.market(
                    BTCUSDT_BINANCE.symbol,
                    OrderSide.BUY,
                    Quantity("1.00000000"),
                )

                self.strategy.submit_order(order)

        stats_file = "perf_live_execution.prof"
        cProfile.runctx("self.loop.run_until_complete(run_test())", globals(),
                        locals(), stats_file)
        s = pstats.Stats(stats_file)
        s.strip_dirs().sort_stats("time").print_stats()
class ExecutionCacheTests(unittest.TestCase):
    def setUp(self):
        # Fixture Setup
        clock = TestClock()
        logger = TestLogger(clock)

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

        self.strategy = TradingStrategy(order_id_tag="001")
        self.strategy.register_trader(
            TraderId("TESTER", "000"),
            clock,
            logger,
        )

        exec_db = BypassExecutionDatabase(trader_id=self.trader_id,
                                          logger=logger)
        self.cache = ExecutionCache(database=exec_db, logger=logger)

    def test_cache_accounts_with_no_accounts(self):
        # Arrange
        # Act
        self.cache.cache_accounts()

        # Assert
        self.assertTrue(True)  # No exception raised

    def test_cache_orders_with_no_orders(self):
        # Arrange
        # Act
        self.cache.cache_orders()

        # Assert
        self.assertTrue(True)  # No exception raised

    def test_cache_positions_with_no_positions(self):
        # Arrange
        # Act
        self.cache.cache_positions()

        # Assert
        self.assertTrue(True)  # No exception raised

    def test_build_index_with_no_objects(self):
        # Arrange
        # Act
        self.cache.build_index()

        # Assert
        self.assertTrue(True)  # No exception raised

    def test_add_account(self):
        # Arrange
        initial = TestStubs.event_account_state()
        account = Account(initial)

        # Act
        self.cache.add_account(account)

        # Assert
        self.assertEqual(account, self.cache.load_account(account.id))

    def test_load_account(self):
        # Arrange
        initial = TestStubs.event_account_state()
        account = Account(initial)

        self.cache.add_account(account)

        # Act
        result = self.cache.load_account(account.id)

        # Assert
        self.assertEqual(account, result)

    def test_account_for_venue(self):
        # Arrange
        # Act
        result = self.cache.account_for_venue(Venue("SIM"))

        # Assert
        self.assertIsNone(result)

    def test_accounts_when_no_accounts_returns_empty_list(self):
        # Arrange
        # Act
        result = self.cache.accounts()

        # Assert
        self.assertEqual([], result)

    def test_get_strategy_ids_with_no_ids_returns_empty_set(self):
        # Arrange
        # Act
        result = self.cache.strategy_ids()

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

    def test_get_order_ids_with_no_ids_returns_empty_set(self):
        # Arrange
        # Act
        result = self.cache.order_ids()

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

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

        # Act
        result = self.cache.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.cache.position_exists(PositionId("P-123456")))

    def test_order_exists_when_no_order_returns_false(self):
        # Arrange
        # Act
        # Assert
        self.assertFalse(self.cache.order_exists(ClientOrderId("O-123456")))

    def test_position_when_no_position_returns_none(self):
        # Arrange
        position_id = PositionId("P-123456")

        # Act
        result = self.cache.position(position_id)

        # Assert
        self.assertIsNone(result)

    def test_order_when_no_order_returns_none(self):
        # Arrange
        order_id = ClientOrderId("O-201908080101-000-001")

        # Act
        result = self.cache.order(order_id)

        # Assert
        self.assertIsNone(result)

    def test_strategy_id_for_position_when_no_strategy_registered_returns_none(
            self):
        # Arrange
        # Act
        # Assert
        self.assertIsNone(
            self.cache.strategy_id_for_position(PositionId("P-123456")))

    def test_add_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        position_id = PositionId('P-1')

        # Act
        self.cache.add_order(order, position_id)

        # Assert
        self.assertIn(order.cl_ord_id, self.cache.order_ids())
        self.assertIn(order.cl_ord_id,
                      self.cache.order_ids(instrument_id=order.instrument_id))
        self.assertIn(order.cl_ord_id,
                      self.cache.order_ids(strategy_id=self.strategy.id))
        self.assertNotIn(
            order.cl_ord_id,
            self.cache.order_ids(strategy_id=StrategyId("S", "ZX1")))
        self.assertIn(
            order.cl_ord_id,
            self.cache.order_ids(instrument_id=order.instrument_id,
                                 strategy_id=self.strategy.id))
        self.assertIn(order, self.cache.orders())
        self.assertEqual(OrderId.null(), self.cache.order_id(order.cl_ord_id))
        self.assertIsNone(self.cache.cl_ord_id(order.id))

    def test_load_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        position_id = PositionId('P-1')
        self.cache.add_order(order, position_id)

        # Act
        result = self.cache.load_order(order.cl_ord_id)

        # Assert
        self.assertEqual(order, result)

    def test_add_position(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        position_id = PositionId('P-1')
        self.cache.add_order(order, position_id)

        order_filled = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            position_id=PositionId('P-1'),
            fill_price=Price("1.00000"),
        )

        position = Position(order_filled)

        # Act
        self.cache.add_position(position)

        # Assert
        self.assertTrue(self.cache.position_exists(position.id))
        self.assertIn(position.id, self.cache.position_ids())
        self.assertIn(position, self.cache.positions())
        self.assertIn(position, self.cache.positions_open())
        self.assertIn(
            position,
            self.cache.positions_open(instrument_id=position.instrument_id))
        self.assertIn(position,
                      self.cache.positions_open(strategy_id=self.strategy.id))
        self.assertIn(
            position,
            self.cache.positions_open(instrument_id=position.instrument_id,
                                      strategy_id=self.strategy.id))
        self.assertNotIn(position, self.cache.positions_closed())
        self.assertNotIn(
            position,
            self.cache.positions_closed(instrument_id=position.instrument_id))
        self.assertNotIn(
            position,
            self.cache.positions_closed(strategy_id=self.strategy.id))
        self.assertNotIn(
            position,
            self.cache.positions_closed(instrument_id=position.instrument_id,
                                        strategy_id=self.strategy.id))

    def test_load_position(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        position_id = PositionId('P-1')
        self.cache.add_order(order, position_id)

        order_filled = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            position_id=PositionId('P-1'),
            fill_price=Price("1.00000"),
        )

        position = Position(order_filled)
        self.cache.add_position(position)

        # Act
        result = self.cache.load_position(position.id)

        # Assert
        self.assertEqual(position, result)

    def test_update_order_for_accepted_order(self):
        # Arrange
        order = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            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_working())
        self.assertIn(
            order,
            self.cache.orders_working(instrument_id=order.instrument_id))
        self.assertIn(order,
                      self.cache.orders_working(strategy_id=self.strategy.id))
        self.assertIn(
            order,
            self.cache.orders_working(instrument_id=order.instrument_id,
                                      strategy_id=self.strategy.id))
        self.assertNotIn(order, self.cache.orders_completed())
        self.assertNotIn(
            order,
            self.cache.orders_completed(instrument_id=order.instrument_id))
        self.assertNotIn(
            order, self.cache.orders_completed(strategy_id=self.strategy.id))
        self.assertNotIn(
            order,
            self.cache.orders_completed(instrument_id=order.instrument_id,
                                        strategy_id=self.strategy.id))
        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_update_order_for_completed_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(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)

        order.apply(
            TestStubs.event_order_filled(order,
                                         instrument=AUDUSD_SIM,
                                         fill_price=Price("1.00001")), )

        # 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_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.id, self.cache.order_id(order.cl_ord_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_update_position_for_open_position(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        position_id = PositionId('P-1')
        self.cache.add_order(order1, position_id)
        order1.apply(TestStubs.event_order_submitted(order1))
        self.cache.update_order(order1)

        order1.apply(TestStubs.event_order_accepted(order1))
        self.cache.update_order(order1)
        order1_filled = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=PositionId('P-1'),
            fill_price=Price("1.00001"),
        )

        position = Position(order1_filled)

        # Act
        self.cache.add_position(position)

        # Assert
        self.assertTrue(self.cache.position_exists(position.id))
        self.assertIn(position.id, self.cache.position_ids())
        self.assertIn(position, self.cache.positions())
        self.assertIn(position, self.cache.positions_open())
        self.assertIn(
            position,
            self.cache.positions_open(instrument_id=position.instrument_id))
        self.assertIn(position,
                      self.cache.positions_open(strategy_id=self.strategy.id))
        self.assertIn(
            position,
            self.cache.positions_open(instrument_id=position.instrument_id,
                                      strategy_id=self.strategy.id))
        self.assertNotIn(position, self.cache.positions_closed())
        self.assertNotIn(
            position,
            self.cache.positions_closed(instrument_id=position.instrument_id))
        self.assertNotIn(
            position,
            self.cache.positions_closed(strategy_id=self.strategy.id))
        self.assertNotIn(
            position,
            self.cache.positions_closed(instrument_id=position.instrument_id,
                                        strategy_id=self.strategy.id))
        self.assertEqual(position, self.cache.position(position_id))
        self.assertEqual(1, self.cache.positions_open_count())
        self.assertEqual(0, self.cache.positions_closed_count())
        self.assertEqual(1, self.cache.positions_total_count())

    def test_update_position_for_closed_position(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        position_id = PositionId('P-1')
        self.cache.add_order(order1, position_id)
        order1.apply(TestStubs.event_order_submitted(order1))
        self.cache.update_order(order1)

        order1.apply(TestStubs.event_order_accepted(order1))
        self.cache.update_order(order1)
        order1_filled = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=PositionId('P-1'),
            fill_price=Price("1.00001"),
        )

        position = Position(order1_filled)
        self.cache.add_position(position)

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

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

        order2.apply(TestStubs.event_order_accepted(order2))
        self.cache.update_order(order2)
        order2_filled = TestStubs.event_order_filled(
            order2,
            instrument=AUDUSD_SIM,
            position_id=PositionId('P-1'),
            fill_price=Price("1.00001"),
        )

        position.apply(order2_filled)

        # Act
        self.cache.update_position(position)

        # Assert
        self.assertTrue(self.cache.position_exists(position.id))
        self.assertIn(position.id, self.cache.position_ids())
        self.assertIn(position, self.cache.positions())
        self.assertIn(position, self.cache.positions_closed())
        self.assertIn(
            position,
            self.cache.positions_closed(instrument_id=position.instrument_id))
        self.assertIn(
            position,
            self.cache.positions_closed(strategy_id=self.strategy.id))
        self.assertIn(
            position,
            self.cache.positions_closed(instrument_id=position.instrument_id,
                                        strategy_id=self.strategy.id))
        self.assertNotIn(position, self.cache.positions_open())
        self.assertNotIn(
            position,
            self.cache.positions_open(instrument_id=position.instrument_id))
        self.assertNotIn(
            position, self.cache.positions_open(strategy_id=self.strategy.id))
        self.assertNotIn(
            position,
            self.cache.positions_open(instrument_id=position.instrument_id,
                                      strategy_id=self.strategy.id))
        self.assertEqual(position, self.cache.position(position_id))
        self.assertEqual(0, self.cache.positions_open_count())
        self.assertEqual(1, self.cache.positions_closed_count())
        self.assertEqual(1, self.cache.positions_total_count())

    def test_update_account(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)

        self.cache.add_account(account)

        # Act
        self.cache.update_account(account)

        # Assert
        self.assertTrue(True)  # No exceptions raised

    def test_delete_strategy(self):
        # Arrange
        self.cache.update_strategy(self.strategy)

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

        # Assert
        self.assertNotIn(self.strategy.id, self.cache.strategy_ids())

    def test_check_residuals(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        position1_id = PositionId('P-1')
        self.cache.add_order(order1, position1_id)

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

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

        order1_filled = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=position1_id,
            fill_price=Price("1.00000"),
        )

        position1 = Position(order1_filled)
        self.cache.update_order(order1)
        self.cache.add_position(position1)

        order2 = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.0000"),
        )

        position2_id = PositionId('P-2')
        self.cache.add_order(order2, position2_id)

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

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

        # Act
        self.cache.check_residuals()

        # Assert
        self.assertTrue(True)  # No exception raised

    def test_reset(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        position1_id = PositionId('P-1')
        self.cache.add_order(order1, position1_id)

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

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

        order1_filled = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=position1_id,
            fill_price=Price("1.00000"),
        )
        position1 = Position(order1_filled)
        self.cache.update_order(order1)
        self.cache.add_position(position1)

        order2 = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        position2_id = PositionId('P-2')
        self.cache.add_order(order2, position2_id)

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

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

        self.cache.update_order(order2)

        # Act
        self.cache.reset()

        # Assert
        self.assertEqual(0, len(self.cache.strategy_ids()))
        self.assertEqual(0, self.cache.orders_total_count())
        self.assertEqual(0, self.cache.positions_total_count())

    def test_flush_db(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        position1_id = PositionId('P-1')
        self.cache.add_order(order1, position1_id)

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

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

        order1_filled = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=position1_id,
            fill_price=Price("1.00000"),
        )

        position1 = Position(order1_filled)
        self.cache.update_order(order1)
        self.cache.add_position(position1)

        order2 = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        position2_id = PositionId('P-2')
        self.cache.add_order(order2, position2_id)
        order2.apply(TestStubs.event_order_submitted(order2))
        self.cache.update_order(order2)

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

        # Act
        self.cache.reset()
        self.cache.flush_db()

        # Assert
        self.assertTrue(True)  # No exception raised
Beispiel #4
0
    def test_multiple_strategy_positions_one_active_one_closed(self):
        # Arrange
        self.exec_engine.start()

        strategy1 = TradingStrategy(order_id_tag="001")
        strategy1.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        strategy2 = TradingStrategy(order_id_tag="002")
        strategy2.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy1)
        self.exec_engine.register_strategy(strategy2)

        order1 = strategy1.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        order2 = strategy1.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
            Price("1.00000"),
        )

        order3 = strategy2.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy1.id,
            PositionId.null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position_id1 = PositionId('P-1')

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy1.id,
            position_id1,
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        submit_order3 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy2.id,
            PositionId.null(),
            order3,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position_id2 = PositionId('P-2')

        # Act
        self.exec_engine.execute(submit_order1)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(TestStubs.event_order_filled(order1, AUDUSD_SIM, position_id1))

        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(TestStubs.event_order_filled(order2, AUDUSD_SIM, position_id1))

        self.exec_engine.execute(submit_order3)
        self.exec_engine.process(TestStubs.event_order_submitted(order3))
        self.exec_engine.process(TestStubs.event_order_accepted(order3))
        self.exec_engine.process(TestStubs.event_order_filled(order3, AUDUSD_SIM, position_id2))

        # Assert
        # Already tested .is_position_active and .is_position_closed above
        self.assertTrue(self.cache.position_exists(position_id1))
        self.assertTrue(self.cache.position_exists(position_id2))
        self.assertIn(position_id1, self.cache.position_ids(strategy_id=strategy1.id))
        self.assertIn(position_id2, self.cache.position_ids(strategy_id=strategy2.id))
        self.assertIn(position_id1, self.cache.position_ids())
        self.assertIn(position_id2, self.cache.position_ids())
        self.assertEqual(0, len(self.cache.positions_open(strategy_id=strategy1.id)))
        self.assertEqual(1, len(self.cache.positions_open(strategy_id=strategy2.id)))
        self.assertEqual(1, len(self.cache.positions_open()))
        self.assertEqual(1, len(self.cache.positions_closed()))
        self.assertEqual(2, len(self.cache.positions()))
        self.assertNotIn(position_id1, self.cache.position_open_ids(strategy_id=strategy1.id))
        self.assertIn(position_id2, self.cache.position_open_ids(strategy_id=strategy2.id))
        self.assertNotIn(position_id1, self.cache.position_open_ids())
        self.assertIn(position_id2, self.cache.position_open_ids())
        self.assertIn(position_id1, self.cache.position_closed_ids(strategy_id=strategy1.id))
        self.assertNotIn(position_id2, self.cache.position_closed_ids(strategy_id=strategy2.id))
        self.assertIn(position_id1, self.cache.position_closed_ids())
        self.assertNotIn(position_id2, self.cache.position_closed_ids())
        self.assertEqual(2, self.cache.positions_total_count())
        self.assertEqual(1, self.cache.positions_open_count())
        self.assertEqual(1, self.cache.positions_closed_count())
Beispiel #5
0
    def test_flip_position_on_opposite_filled_same_position_buy(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)

        order1 = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
        )

        order2 = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(150000),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position_id = PositionId("P-000-AUD/USD.SIM-1")

        self.exec_engine.execute(submit_order1)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(TestStubs.event_order_filled(order1, AUDUSD_SIM, position_id))

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            position_id,
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(TestStubs.event_order_filled(order2, AUDUSD_SIM, position_id))

        # Assert
        position_id_flipped = PositionId("P-000-AUD/USD.SIM-1F")
        position_flipped = self.cache.position(position_id_flipped)

        self.assertEqual(50000, position_flipped.relative_quantity)
        self.assertEqual(50000, position_flipped.last_event.fill_qty)
        self.assertEqual(150000, position_flipped.last_event.cum_qty)
        self.assertEqual(0, position_flipped.last_event.leaves_qty)
        self.assertEqual(Quantity(100000), self.cache.order(order1.cl_ord_id).last_event.cum_qty)
        self.assertEqual(0, self.cache.order(order1.cl_ord_id).last_event.leaves_qty)
        self.assertTrue(self.cache.position_exists(position_id))
        self.assertTrue(self.cache.position_exists(position_id_flipped))
        self.assertTrue(self.cache.is_position_closed(position_id))
        self.assertTrue(self.cache.is_position_open(position_id_flipped))
        self.assertIn(position_id, self.cache.position_ids())
        self.assertIn(position_id, self.cache.position_ids(strategy_id=strategy.id))
        self.assertIn(position_id_flipped, self.cache.position_ids())
        self.assertIn(position_id_flipped, self.cache.position_ids(strategy_id=strategy.id))
        self.assertEqual(2, self.cache.positions_total_count())
        self.assertEqual(1, self.cache.positions_open_count())
        self.assertEqual(1, self.cache.positions_closed_count())
Beispiel #6
0
    def test_add_to_existing_position_on_order_fill(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)

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

        order2 = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        self.exec_engine.execute(submit_order1)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(TestStubs.event_order_filled(order1, AUDUSD_SIM))

        expected_position_id = PositionId("O-19700101-000000-000-001-1")  # Stubbed from order id?

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            expected_position_id,
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(TestStubs.event_order_filled(order2, AUDUSD_SIM, expected_position_id))

        # Assert
        self.assertTrue(self.cache.position_exists(TestStubs.event_order_filled(order1, AUDUSD_SIM,).position_id))
        self.assertTrue(self.cache.is_position_open(expected_position_id))
        self.assertFalse(self.cache.is_position_closed(expected_position_id))
        self.assertEqual(Position, type(self.cache.position(expected_position_id)))
        self.assertEqual(0, len(self.cache.positions_closed(strategy_id=strategy.id)))
        self.assertEqual(0, len(self.cache.positions_closed()))
        self.assertEqual(1, len(self.cache.positions_open(strategy_id=strategy.id)))
        self.assertEqual(1, len(self.cache.positions_open()))
        self.assertEqual(1, self.cache.positions_total_count())
        self.assertEqual(1, self.cache.positions_open_count())
        self.assertEqual(0, self.cache.positions_closed_count())
Beispiel #7
0
    def test_close_position_on_order_fill(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)

        order1 = strategy.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        order2 = strategy.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
            Price("1.00000"),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position_id = PositionId("P-1")

        self.exec_engine.execute(submit_order1)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(TestStubs.event_order_filled(order1, AUDUSD_SIM, position_id))

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            position_id,
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(TestStubs.event_order_filled(order2, AUDUSD_SIM, position_id))

        # # Assert
        self.assertTrue(self.cache.position_exists(position_id))
        self.assertFalse(self.cache.is_position_open(position_id))
        self.assertTrue(self.cache.is_position_closed(position_id))
        self.assertEqual(position_id, self.cache.position(position_id).id)
        self.assertEqual(position_id, self.cache.positions(strategy_id=strategy.id)[0].id)
        self.assertEqual(position_id, self.cache.positions()[0].id)
        self.assertEqual(0, len(self.cache.positions_open(strategy_id=strategy.id)))
        self.assertEqual(0, len(self.cache.positions_open()))
        self.assertEqual(position_id, self.cache.positions_closed(strategy_id=strategy.id)[0].id)
        self.assertEqual(position_id, self.cache.positions_closed()[0].id)
        self.assertNotIn(position_id, self.cache.position_open_ids(strategy_id=strategy.id))
        self.assertNotIn(position_id, self.cache.position_open_ids())
        self.assertEqual(1, self.cache.positions_total_count())
        self.assertEqual(0, self.cache.positions_open_count())
        self.assertEqual(1, self.cache.positions_closed_count())
    def test_flip_position_on_opposite_filled_same_position(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)

        order1 = strategy.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000),
        )

        order2 = strategy.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.SELL,
            Quantity(150000),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.py_null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position_id = PositionId("P-000-AUD/USD.FXCM-1")

        self.exec_engine.execute(submit_order1)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(
            TestStubs.event_order_filled(order1, position_id))

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            position_id,
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(
            TestStubs.event_order_filled(order2, position_id))

        position_id_flipped = PositionId("P-000-AUD/USD.FXCM-1F")
        order_id_flipped = ClientOrderId(order2.cl_ord_id.value + 'F')

        # Assert
        self.assertTrue(self.cache.position_exists(position_id))
        self.assertTrue(self.cache.position_exists(position_id_flipped))
        self.assertTrue(self.cache.is_position_closed(position_id))
        self.assertTrue(self.cache.is_position_open(position_id_flipped))
        self.assertFalse(self.cache.is_flat(strategy_id=strategy.id))
        self.assertTrue(position_id in self.cache.position_ids())
        self.assertTrue(position_id in self.cache.position_ids(
            strategy_id=strategy.id))
        self.assertTrue(position_id_flipped in self.cache.position_ids())
        self.assertTrue(position_id_flipped in self.cache.position_ids(
            strategy_id=strategy.id))
        self.assertTrue(order_id_flipped,
                        self.cache.position_exists_for_order(order_id_flipped))
        self.assertEqual(2, self.cache.positions_total_count())
        self.assertEqual(1, self.cache.positions_open_count())
        self.assertEqual(1, self.cache.positions_closed_count())
    def test_multiple_strategy_positions_opened(self):
        # Arrange
        strategy1 = TradingStrategy(order_id_tag="001")
        strategy1.register_trader(
            TraderId("TESTER", "000"),
            clock=self.clock,
            uuid_factory=TestUUIDFactory(),
            logger=self.logger,
        )

        strategy2 = TradingStrategy(order_id_tag="002")
        strategy2.register_trader(
            TraderId("TESTER", "000"),
            clock=self.clock,
            uuid_factory=TestUUIDFactory(),
            logger=self.logger,
        )

        self.exec_engine.register_strategy(strategy1)
        self.exec_engine.register_strategy(strategy2)

        order1 = strategy1.order_factory.stop(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        order2 = strategy2.order_factory.stop(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy1.id,
            PositionId.py_null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy2.id,
            PositionId.py_null(),
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position1_id = PositionId('P-1')
        position2_id = PositionId('P-2')

        # Act
        self.exec_engine.execute(submit_order1)
        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(
            TestStubs.event_order_filled(order1, position1_id))
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(
            TestStubs.event_order_filled(order2, position2_id))

        # Assert
        self.assertTrue(self.cache.position_exists(position1_id))
        self.assertTrue(self.cache.position_exists(position2_id))
        self.assertTrue(self.cache.is_position_open(position1_id))
        self.assertTrue(self.cache.is_position_open(position2_id))
        self.assertFalse(self.cache.is_position_closed(position1_id))
        self.assertFalse(self.cache.is_position_closed(position2_id))
        self.assertFalse(self.cache.is_flat(strategy_id=strategy1.id))
        self.assertFalse(self.cache.is_flat(strategy_id=strategy2.id))
        self.assertFalse(self.cache.is_flat())
        self.assertEqual(Position, type(self.cache.position(position1_id)))
        self.assertEqual(Position, type(self.cache.position(position2_id)))
        self.assertTrue(position1_id in self.cache.position_ids(
            strategy_id=strategy1.id))
        self.assertTrue(position2_id in self.cache.position_ids(
            strategy_id=strategy2.id))
        self.assertTrue(position1_id in self.cache.position_ids())
        self.assertTrue(position2_id in self.cache.position_ids())
        self.assertEqual(2, len(self.cache.position_open_ids()))
        self.assertEqual(
            1, len(self.cache.positions_open(strategy_id=strategy1.id)))
        self.assertEqual(
            1, len(self.cache.positions_open(strategy_id=strategy2.id)))
        self.assertEqual(
            1, len(self.cache.positions_open(strategy_id=strategy2.id)))
        self.assertEqual(2, len(self.cache.positions_open()))
        self.assertEqual(
            1, len(self.cache.positions_open(strategy_id=strategy1.id)))
        self.assertEqual(
            1, len(self.cache.positions_open(strategy_id=strategy2.id)))
        self.assertTrue(position1_id in self.cache.position_open_ids(
            strategy_id=strategy1.id))
        self.assertTrue(position2_id in self.cache.position_open_ids(
            strategy_id=strategy2.id))
        self.assertTrue(position1_id in self.cache.position_open_ids())
        self.assertTrue(position2_id in self.cache.position_open_ids())
        self.assertTrue(position1_id not in self.cache.position_closed_ids(
            strategy_id=strategy1.id))
        self.assertTrue(position2_id not in self.cache.position_closed_ids(
            strategy_id=strategy2.id))
        self.assertTrue(position1_id not in self.cache.position_closed_ids())
        self.assertTrue(position2_id not in self.cache.position_closed_ids())
        self.assertEqual(2, self.cache.positions_total_count())
        self.assertEqual(2, self.cache.positions_open_count())
        self.assertEqual(0, self.cache.positions_closed_count())
Beispiel #10
0
    def test_handle_order_fill_event(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_position_id = PositionId(
            "O-19700101-000000-000-001-1")  # Stubbed from order id?

        # Assert
        self.assertTrue(self.cache.position_exists(expected_position_id))
        self.assertTrue(self.cache.is_position_open(expected_position_id))
        self.assertFalse(self.cache.is_position_closed(expected_position_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_position_id)))
        self.assertTrue(expected_position_id in self.cache.position_ids())
        self.assertTrue(
            expected_position_id not in self.cache.position_closed_ids(
                strategy_id=strategy.id))
        self.assertTrue(
            expected_position_id not in self.cache.position_closed_ids())
        self.assertTrue(expected_position_id in self.cache.position_open_ids(
            strategy_id=strategy.id))
        self.assertTrue(expected_position_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))
Beispiel #11
0
        async def run_test():
            # Arrange
            self.engine.start()

            strategy = TradingStrategy(order_id_tag="001")
            strategy.register_trader(
                TraderId("TESTER", "000"),
                self.clock,
                self.logger,
            )

            self.engine.register_strategy(strategy)

            order = strategy.order_factory.limit(
                AUDUSD_SIM.id,
                OrderSide.BUY,
                Quantity(100000),
                Price("1.00000"),
            )

            submit_order = SubmitOrder(
                AUDUSD_SIM.id.venue.client_id,
                self.trader_id,
                self.account_id,
                strategy.id,
                PositionId.null(),
                order,
                self.uuid_factory.generate(),
                self.clock.timestamp_ns(),
            )

            self.engine.execute(submit_order)
            self.engine.process(TestStubs.event_order_submitted(order))
            self.engine.process(TestStubs.event_order_accepted(order))

            report = OrderStatusReport(
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),  # <-- from stub event
                order_state=OrderState.FILLED,
                filled_qty=Quantity(100000),
                timestamp_ns=0,
            )

            trade1 = ExecutionReport(
                execution_id=ExecutionId("1"),
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),
                last_qty=Decimal(50000),
                last_px=Decimal("1.00000"),
                commission_amount=Decimal("5.0"),
                commission_currency="USD",
                liquidity_side=LiquiditySide.MAKER,
                execution_ns=0,
                timestamp_ns=0,
            )

            trade2 = ExecutionReport(
                execution_id=ExecutionId("2"),
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),
                last_qty=Decimal(50000),
                last_px=Decimal("1.00000"),
                commission_amount=Decimal("2.0"),
                commission_currency="USD",
                liquidity_side=LiquiditySide.MAKER,
                execution_ns=0,
                timestamp_ns=0,
            )

            self.client.add_order_status_report(report)
            self.client.add_trades_list(VenueOrderId("1"), [trade1, trade2])

            await asyncio.sleep(0.01)

            # Act
            result = await self.engine.reconcile_state()
            self.engine.stop()

            # Assert
            assert result
class TestRedisExecutionDatabase:
    def setup(self):
        # Fixture Setup
        self.clock = TestClock()
        self.logger = Logger(self.clock)
        self.trader_id = TraderId("TESTER-000")

        self.strategy = TradingStrategy(order_id_tag="001")
        self.strategy.register_trader(self.trader_id, self.clock, self.logger)

        config = {
            "host": "localhost",
            "port": 6379,
        }

        self.database = RedisCacheDatabase(
            trader_id=self.trader_id,
            logger=self.logger,
            instrument_serializer=MsgPackInstrumentSerializer(),
            command_serializer=MsgPackCommandSerializer(),
            event_serializer=MsgPackEventSerializer(),
            config=config,
        )

        self.test_redis = redis.Redis(host="localhost", port=6379, db=0)

    def teardown(self):
        # Tests will start failing if redis is not flushed on tear down
        self.test_redis.flushall(
        )  # Comment this line out to preserve data between tests

    def test_add_currency(self):
        # Arrange
        currency = Currency(
            code="1INCH",
            precision=8,
            iso4217=0,
            name="1INCH",
            currency_type=CurrencyType.CRYPTO,
        )

        # Act
        self.database.add_currency(currency)

        # Assert
        assert self.database.load_currency(currency.code) == currency

    def test_add_account(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)

        # Act
        self.database.add_account(account)

        # Assert
        assert self.database.load_account(account.id) == account

    def test_add_instrument(self):
        # Arrange, Act
        self.database.add_instrument(AUDUSD_SIM)

        # Assert
        assert self.database.load_instrument(AUDUSD_SIM.id) == AUDUSD_SIM

    def test_add_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        # Act
        self.database.add_order(order)

        # Assert
        assert self.database.load_order(order.client_order_id) == order

    def test_add_position(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        self.database.add_instrument(AUDUSD_SIM)
        self.database.add_order(order)

        position_id = PositionId("P-1")
        fill = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            position_id=position_id,
            last_px=Price.from_str("1.00000"),
        )

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

        # Act
        self.database.add_position(position)

        # Assert
        assert self.database.load_position(position.id) == position

    def test_update_account(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)
        self.database.add_account(account)

        # Act
        self.database.update_account(account)

        # Assert
        assert self.database.load_account(account.id) == account

    def test_update_order_for_working_order(self):
        # Arrange
        order = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00000"),
        )

        self.database.add_order(order)

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

        order.apply(TestStubs.event_order_accepted(order))

        # Act
        self.database.update_order(order)

        # Assert
        assert self.database.load_order(order.client_order_id) == order

    def test_update_order_for_completed_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        self.database.add_order(order)

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

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

        fill = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            last_px=Price.from_str("1.00001"),
        )

        order.apply(fill)

        # Act
        self.database.update_order(order)

        # Assert
        assert self.database.load_order(order.client_order_id) == order

    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_update_strategy(self):
        # Arrange
        strategy = MockStrategy(
            TestStubs.bartype_btcusdt_binance_100tick_last())
        strategy.register_trader(self.trader_id, self.clock, self.logger)

        # Act
        self.database.update_strategy(strategy)
        result = self.database.load_strategy(strategy.id)

        # Assert
        assert result == {"UserState": b"1"}

    def test_load_account_when_no_account_in_database_returns_none(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)

        # Act
        result = self.database.load_account(account.id)

        # Assert
        assert result is None

    def test_load_account_when_account_in_database_returns_account(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)
        self.database.add_account(account)

        # Act
        result = self.database.load_account(account.id)

        # Assert
        assert result == account

    def test_load_order_when_no_order_in_database_returns_none(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        # Act
        result = self.database.load_order(order.client_order_id)

        # Assert
        assert result is None

    def test_load_order_when_market_order_in_database_returns_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        self.database.add_order(order)

        # Act
        result = self.database.load_order(order.client_order_id)

        # Assert
        assert result == order

    def test_load_order_when_limit_order_in_database_returns_order(self):
        # Arrange
        order = self.strategy.order_factory.limit(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00000"),
        )

        self.database.add_order(order)

        # Act
        result = self.database.load_order(order.client_order_id)

        # Assert
        assert result == order

    def test_load_order_when_stop_market_order_in_database_returns_order(self):
        # Arrange
        order = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00000"),
        )

        self.database.add_order(order)

        # Act
        result = self.database.load_order(order.client_order_id)

        # Assert
        assert result == order

    def test_load_order_when_stop_limit_order_in_database_returns_order(self):
        # Arrange
        order = self.strategy.order_factory.stop_limit(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            price=Price.from_str("1.00000"),
            trigger=Price.from_str("1.00010"),
        )

        self.database.add_order(order)

        # Act
        result = self.database.load_order(order.client_order_id)

        # Assert
        assert result == order
        assert result.price == order.price
        assert result.trigger == order.trigger

    def test_load_position_when_no_position_in_database_returns_none(self):
        # Arrange
        position_id = PositionId("P-1")

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

        # Assert
        assert result is None

    def test_load_order_when_position_in_database_returns_position(self):
        # Arrange
        self.database.add_instrument(AUDUSD_SIM)

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

        self.database.add_order(order)

        position_id = PositionId("P-1")
        fill = TestStubs.event_order_filled(
            order,
            instrument=AUDUSD_SIM,
            position_id=position_id,
            last_px=Price.from_str("1.00000"),
        )

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

        self.database.add_position(position)

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

        # Assert
        assert result == position

    def test_load_accounts_when_no_accounts_returns_empty_dict(self):
        # Arrange
        # Act
        result = self.database.load_accounts()

        # Assert
        assert result == {}

    def test_load_accounts_cache_when_one_account_in_database(self):
        # Arrange
        event = TestStubs.event_account_state()
        account = Account(event)
        self.database.add_account(account)

        # Act
        # Assert
        assert self.database.load_accounts() == {account.id: account}

    def test_load_orders_cache_when_no_orders(self):
        # Arrange
        # Act
        self.database.load_orders()

        # Assert
        assert self.database.load_orders() == {}

    def test_load_orders_cache_when_one_order_in_database(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        self.database.add_order(order)

        # Act
        result = self.database.load_orders()

        # Assert
        assert result == {order.client_order_id: order}

    def test_load_positions_cache_when_no_positions(self):
        # Arrange
        # Act
        self.database.load_positions()

        # Assert
        assert self.database.load_positions() == {}

    def test_load_positions_cache_when_one_position_in_database(self):
        # Arrange
        self.database.add_instrument(AUDUSD_SIM)

        order1 = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00000"),
        )

        self.database.add_order(order1)

        position_id = PositionId("P-1")
        order1.apply(TestStubs.event_order_submitted(order1))
        order1.apply(TestStubs.event_order_accepted(order1))
        order1.apply(
            TestStubs.event_order_filled(
                order1,
                instrument=AUDUSD_SIM,
                position_id=position_id,
                last_px=Price.from_str("1.00001"),
            ))

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

        # Act
        result = self.database.load_positions()

        # Assert
        assert result == {position.id: position}

    def test_delete_strategy(self):
        # Arrange
        # Act
        self.database.delete_strategy(self.strategy.id)
        result = self.database.load_strategy(self.strategy.id)

        # Assert
        assert result == {}

    def test_flush(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        self.database.add_order(order1)

        position1_id = PositionId("P-1")
        fill = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=position1_id,
            last_px=Price.from_str("1.00000"),
        )

        position1 = Position(instrument=AUDUSD_SIM, fill=fill)
        self.database.update_order(order1)
        self.database.add_position(position1)

        order2 = self.strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00000"),
        )

        self.database.add_order(order2)

        order2.apply(TestStubs.event_order_submitted(order2))
        order2.apply(TestStubs.event_order_accepted(order2))

        self.database.update_order(order2)

        # Act
        self.database.flush()

        # Assert
        assert self.database.load_order(order1.client_order_id) is None
        assert self.database.load_order(order2.client_order_id) is None
        assert self.database.load_position(position1.id) is None