示例#1
0
    def setUp(self):
        # Fixture Setup
        clock = TestClock()
        uuid_factory = TestUUIDFactory()
        logger = TestLogger(clock)

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

        self.strategy = EmptyStrategy(order_id_tag="001")
        self.strategy.register_trader(
            TraderId("TESTER", "000"),
            clock,
            uuid_factory,
            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 test_trader_detects_none_unique_identifiers(self):
        # Arrange
        strategies = [EmptyStrategy("000"), EmptyStrategy("000")]

        # Act
        self.assertRaises(ValueError, self.trader.initialize_strategies,
                          strategies)
示例#3
0
    def setUp(self):
        # Fixture Setup
        usdjpy = TestStubs.instrument_usdjpy()
        data = BacktestDataContainer()
        data.add_instrument(usdjpy)
        data.add_bars(usdjpy.symbol, BarStructure.MINUTE, PriceType.BID,
                      TestDataProvider.usdjpy_1min_bid()[:2000])
        data.add_bars(usdjpy.symbol, BarStructure.MINUTE, PriceType.ASK,
                      TestDataProvider.usdjpy_1min_ask()[:2000])

        clock = TestClock()
        guid_factory = TestGuidFactory()
        logger = TestLogger()
        trader_id = TraderId('TESTER', '000')
        account_id = TestStubs.account_id()

        data_client = BacktestDataClient(data=data,
                                         tick_capacity=100,
                                         clock=clock,
                                         logger=logger)

        self.portfolio = Portfolio(currency=Currency.USD,
                                   clock=clock,
                                   guid_factory=guid_factory,
                                   logger=logger)

        self.analyzer = PerformanceAnalyzer()

        self.exec_db = InMemoryExecutionDatabase(trader_id=trader_id,
                                                 logger=logger)
        self.exec_engine = ExecutionEngine(trader_id=trader_id,
                                           account_id=account_id,
                                           database=self.exec_db,
                                           portfolio=self.portfolio,
                                           clock=clock,
                                           guid_factory=guid_factory,
                                           logger=logger)

        self.exec_client = BacktestExecClient(
            exec_engine=self.exec_engine,
            instruments={usdjpy.symbol: usdjpy},
            config=BacktestConfig(),
            fill_model=FillModel(),
            clock=clock,
            guid_factory=guid_factory,
            logger=logger)
        self.exec_engine.register_client(self.exec_client)

        strategies = [EmptyStrategy('001'), EmptyStrategy('002')]

        self.trader = Trader(trader_id=trader_id,
                             account_id=account_id,
                             strategies=strategies,
                             data_client=data_client,
                             exec_engine=self.exec_engine,
                             clock=clock,
                             guid_factory=guid_factory,
                             logger=logger)
    def test_change_strategies(self):
        # Arrange
        strategies = [EmptyStrategy("003"), EmptyStrategy("004")]

        # Act
        self.trader.initialize_strategies(strategies)

        # Assert
        self.assertTrue(strategies[0].id in self.trader.strategy_states())
        self.assertTrue(strategies[1].id in self.trader.strategy_states())
        self.assertEqual(2, len(self.trader.strategy_states()))
示例#5
0
    def test_run_with_empty_strategy(self):
        # Arrange
        usdjpy = TestStubs.instrument_usdjpy()

        data = BacktestDataContainer()
        data.add_instrument(usdjpy)
        data.add_bars(usdjpy.symbol, BarStructure.MINUTE, PriceType.BID, TestDataProvider.usdjpy_1min_bid())
        data.add_bars(usdjpy.symbol, BarStructure.MINUTE, PriceType.ASK, TestDataProvider.usdjpy_1min_ask())

        strategies = [EmptyStrategy('001')]

        config = BacktestConfig(exec_db_type='in-memory')
        engine = BacktestEngine(
            data=data,
            strategies=strategies,
            fill_model=FillModel(),
            config=config)

        start = datetime(2013, 1, 1, 22, 0, 0, 0, tzinfo=timezone.utc)
        stop = datetime(2013, 8, 10, 0, 0, 0, 0, tzinfo=timezone.utc)

        stats_file = 'perf_stats_backtest_run_empty.prof'
        cProfile.runctx('engine.run(start, stop)', globals(), locals(), stats_file)
        s = pstats.Stats(stats_file)
        s.strip_dirs().sort_stats("time").print_stats()

        self.assertTrue(True)
    def setUp(self):
        self.usdjpy = InstrumentLoader.default_fx_ccy(
            TestStubs.symbol_usdjpy_fxcm())
        data = BacktestDataContainer()
        data.add_instrument(self.usdjpy)
        data.add_bars(self.usdjpy.symbol, BarAggregation.MINUTE, PriceType.BID,
                      TestDataProvider.usdjpy_1min_bid()[:2000])
        data.add_bars(self.usdjpy.symbol, BarAggregation.MINUTE, PriceType.ASK,
                      TestDataProvider.usdjpy_1min_ask()[:2000])

        config = BacktestConfig(
            tick_capacity=1000,
            bar_capacity=1000,
            exec_db_type='in-memory',
            exec_db_flush=False,
            frozen_account=False,
            starting_capital=1000000,
            account_currency=USD,
            short_term_interest_csv_path='default',
            bypass_logging=False,
            level_console=LogLevel.DEBUG,
            level_file=LogLevel.DEBUG,
            level_store=LogLevel.WARNING,
            log_thread=False,
            log_to_file=False,
        )

        self.engine = BacktestEngine(
            data=data,
            strategies=[EmptyStrategy('000')],
            venue=Venue("FXCM"),
            oms_type=OMSType.HEDGING,
            generate_position_ids=True,
            config=config,
        )
    def setUp(self):
        self.usdjpy = TestStubs.instrument_usdjpy()
        data = BacktestDataContainer()
        data.add_instrument(self.usdjpy)
        data.add_bars(self.usdjpy.symbol, BarStructure.MINUTE, PriceType.BID,
                      TestDataProvider.usdjpy_1min_bid()[:2000])
        data.add_bars(self.usdjpy.symbol, BarStructure.MINUTE, PriceType.ASK,
                      TestDataProvider.usdjpy_1min_ask()[:2000])

        config = BacktestConfig(exec_db_type='in-memory',
                                exec_db_flush=False,
                                frozen_account=False,
                                starting_capital=1000000,
                                account_currency=Currency.USD,
                                short_term_interest_csv_path='default',
                                commission_rate_bp=0.20,
                                bypass_logging=True,
                                level_console=LogLevel.DEBUG,
                                level_file=LogLevel.DEBUG,
                                level_store=LogLevel.WARNING,
                                log_thread=False,
                                log_to_file=False)

        self.engine = BacktestEngine(data=data,
                                     strategies=[EmptyStrategy('000')],
                                     config=config)
示例#8
0
    def test_run_with_empty_strategy(self):
        # Arrange
        usdjpy = InstrumentLoader.default_fx_ccy(TestStubs.symbol_usdjpy_fxcm())

        data = BacktestDataContainer()
        data.add_instrument(usdjpy)
        data.add_bars(usdjpy.symbol, BarAggregation.MINUTE, PriceType.BID, TestDataProvider.usdjpy_1min_bid())
        data.add_bars(usdjpy.symbol, BarAggregation.MINUTE, PriceType.ASK, TestDataProvider.usdjpy_1min_ask())

        strategies = [EmptyStrategy("001")]

        config = BacktestConfig(exec_db_type="in-memory")
        engine = BacktestEngine(
            data=data,
            strategies=strategies,
            venue=Venue("FXCM"),
            oms_type=OMSType.HEDGING,
            generate_position_ids=True,
            fill_model=FillModel(),
            config=config,
        )

        start = datetime(2013, 1, 1, 22, 0, 0, 0, tzinfo=pytz.utc)
        stop = datetime(2013, 8, 10, 0, 0, 0, 0, tzinfo=pytz.utc)

        stats_file = "perf_stats_backtest_run_empty.prof"
        cProfile.runctx("engine.run(start, stop)", globals(), locals(), stats_file)
        s = pstats.Stats(stats_file)
        s.strip_dirs().sort_stats("time").print_stats()

        self.assertTrue(True)
    def setUp(self):
        # Fixture Setup
        clock = TestClock()
        logger = TestLogger()

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

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

        self.database = RedisExecutionDatabase(
            trader_id=self.trader_id,
            host='localhost',
            port=6379,
            command_serializer=MsgPackCommandSerializer(),
            event_serializer=MsgPackEventSerializer(),
            logger=logger)

        self.test_redis = redis.Redis(host='localhost', port=6379, db=0)
示例#10
0
    def setUp(self):
        usdjpy = TestStubs.instrument_usdjpy()
        data = BacktestDataContainer()
        data.add_instrument(usdjpy)
        data.add_bars(usdjpy.symbol, BarStructure.MINUTE, PriceType.BID,
                      TestDataProvider.usdjpy_1min_bid()[:2000])
        data.add_bars(usdjpy.symbol, BarStructure.MINUTE, PriceType.ASK,
                      TestDataProvider.usdjpy_1min_ask()[:2000])

        self.engine = BacktestEngine(data=data,
                                     strategies=[EmptyStrategy('000')],
                                     fill_model=FillModel(),
                                     config=BacktestConfig())
    def setUp(self):
        usdjpy = InstrumentLoader.default_fx_ccy(
            TestStubs.symbol_usdjpy_fxcm())
        data = BacktestDataContainer()
        data.add_instrument(usdjpy)
        data.add_bars(usdjpy.symbol, BarAggregation.MINUTE, PriceType.BID,
                      TestDataProvider.usdjpy_1min_bid()[:2000])
        data.add_bars(usdjpy.symbol, BarAggregation.MINUTE, PriceType.ASK,
                      TestDataProvider.usdjpy_1min_ask()[:2000])

        self.engine = BacktestEngine(
            data=data,
            strategies=[EmptyStrategy("000")],
            venue=Venue("FXCM"),
            oms_type=OMSType.HEDGING,
            generate_position_ids=True,
            fill_model=FillModel(),
            config=BacktestConfig(),
        )
    def setUp(self):
        # Fixture Setup
        usdjpy = InstrumentLoader.default_fx_ccy(
            TestStubs.symbol_usdjpy_fxcm())
        data = BacktestDataContainer()
        data.add_instrument(usdjpy)
        data.add_bars(usdjpy.symbol, BarAggregation.MINUTE, PriceType.BID,
                      TestDataProvider.usdjpy_1min_bid()[:2000])
        data.add_bars(usdjpy.symbol, BarAggregation.MINUTE, PriceType.ASK,
                      TestDataProvider.usdjpy_1min_ask()[:2000])

        clock = TestClock()
        uuid_factory = TestUUIDFactory()
        logger = TestLogger(clock)
        trader_id = TraderId("TESTER", "000")
        account_id = TestStubs.account_id()

        self.portfolio = Portfolio(
            clock=clock,
            uuid_factory=uuid_factory,
            logger=logger,
        )

        data_engine = BacktestDataEngine(
            data=data,
            tick_capacity=1000,
            bar_capacity=1000,
            portfolio=self.portfolio,
            clock=clock,
            logger=logger,
        )

        self.analyzer = PerformanceAnalyzer()

        self.exec_db = BypassExecutionDatabase(
            trader_id=trader_id,
            logger=logger,
        )

        self.exec_engine = ExecutionEngine(
            database=self.exec_db,
            portfolio=self.portfolio,
            clock=clock,
            uuid_factory=uuid_factory,
            logger=logger,
        )

        self.market = SimulatedMarket(
            venue=Venue("FXCM"),
            oms_type=OMSType.HEDGING,
            generate_position_ids=True,
            exec_cache=self.exec_engine.cache,
            instruments={usdjpy.symbol: usdjpy},
            config=BacktestConfig(),
            fill_model=FillModel(),
            commission_model=GenericCommissionModel(),
            clock=clock,
            uuid_factory=TestUUIDFactory(),
            logger=logger,
        )

        self.exec_client = BacktestExecClient(
            market=self.market,
            account_id=account_id,
            engine=self.exec_engine,
            logger=logger,
        )

        self.exec_engine.register_client(self.exec_client)

        strategies = [
            EmptyStrategy("001"),
            EmptyStrategy("002"),
        ]

        self.trader = Trader(
            trader_id=trader_id,
            strategies=strategies,
            data_engine=data_engine,
            exec_engine=self.exec_engine,
            clock=clock,
            uuid_factory=uuid_factory,
            logger=logger,
        )
示例#13
0
class RedisExecutionDatabaseTests(unittest.TestCase):

    def setUp(self):
        # Fixture Setup
        clock = TestClock()
        uuid_factory = TestUUIDFactory()
        logger = TestLogger(clock)

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

        self.strategy = EmptyStrategy(order_id_tag="001")
        self.strategy.register_trader(
            TraderId("TESTER", "000"),
            clock,
            uuid_factory,
            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
        pass

    def test_keys(self):
        # Arrange
        # Act
        # Assert
        self.assertEqual("Trader-TESTER-000", self.database.key_trader)
        self.assertEqual("Trader-TESTER-000:Accounts:", self.database.key_accounts)
        self.assertEqual("Trader-TESTER-000:Orders:", self.database.key_orders)
        self.assertEqual("Trader-TESTER-000:Positions:", self.database.key_positions)
        self.assertEqual("Trader-TESTER-000:Strategies:", self.database.key_strategies)

    # TODO: AccountState not finalized (no serialization yet)
    # def test_add_account(self):
    #     # Arrange
    #     event = TestStubs.account_event()
    #     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_FXCM,
            OrderSide.BUY,
            Quantity(100000),
        )

        position_id = PositionId.py_null()

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

        # 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_FXCM,
            OrderSide.BUY,
            Quantity(100000))
        position_id = PositionId('P-1')
        self.database.add_order(order, position_id)

        order_filled = TestStubs.event_order_filled(order, 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))

    # TODO: Investigate why str is deserializing to a list
    # def test_update_account(self):
    #     # Arrange
    #     event = TestStubs.account_event()
    #     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(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

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

        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_FXCM,
            OrderSide.BUY,
            Quantity(100000))
        position_id = PositionId('P-1')
        self.database.add_order(order, position_id)

        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, 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_FXCM,
            OrderSide.BUY,
            Quantity(100000))
        position_id = PositionId('P-1')
        self.database.add_order(order1, position_id)

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

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

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

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

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

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

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

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

        position.apply(filled)

        # Act
        self.database.update_position(position)

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

    def test_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)

    # TODO: Investigate why str is deserializing to a list
    # def test_load_account_when_account_in_database_returns_account(self):
    #     # Arrange
    #     event = TestStubs.account_event()
    #     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_FXCM,
            OrderSide.BUY,
            Quantity(100000))

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

        # Assert
        self.assertIsNone(result)

    def test_load_order_when_order_in_database_returns_order(self):
        # Arrange
        order = self.strategy.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000))
        position_id = PositionId('P-1')
        self.database.add_order(order, position_id)

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

        # Assert
        self.assertEqual(order, result)

    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_FXCM,
            OrderSide.BUY,
            Quantity(100000))
        position_id = PositionId('P-1')
        self.database.add_order(order, position_id)

        order_filled = TestStubs.event_order_filled(order, 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)

    # TODO: Investigate why str is deserializing to a list
    # def test_load_accounts_cache_when_one_account_in_database(self):
    #     # Arrange
    #     event = TestStubs.account_event()
    #     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_FXCM,
            OrderSide.BUY,
            Quantity(100000),
        )

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

        # 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(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

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

        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, 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_can_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_can_flush(self):
        # Arrange
        order1 = self.strategy.order_factory.market(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000))
        position1_id = PositionId('P-1')
        self.database.add_order(order1, position1_id)

        filled = TestStubs.event_order_filled(order1, 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(
            AUDUSD_FXCM,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"))

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

        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()
class RedisExecutionDatabaseTests(unittest.TestCase):

    # These tests require a Redis instance listening on the default port 6379

    def setUp(self):
        # Fixture Setup
        clock = TestClock()
        logger = TestLogger()

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

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

        self.database = RedisExecutionDatabase(
            trader_id=self.trader_id,
            host='localhost',
            port=6379,
            command_serializer=MsgPackCommandSerializer(),
            event_serializer=MsgPackEventSerializer(),
            logger=logger)

        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
        pass

    def test_keys(self):
        # Arrange
        # Act
        # Assert
        self.assertEqual('Trader-TESTER-000', self.database.key_trader)
        self.assertEqual('Trader-TESTER-000:Accounts:', self.database.key_accounts)
        self.assertEqual('Trader-TESTER-000:Orders:', self.database.key_orders)
        self.assertEqual('Trader-TESTER-000:Positions:', self.database.key_positions)
        self.assertEqual('Trader-TESTER-000:Strategies:', self.database.key_strategies)
        self.assertEqual('Trader-TESTER-000:Index:OrderPosition', self.database.key_index_order_position)
        self.assertEqual('Trader-TESTER-000:Index:OrderStrategy', self.database.key_index_order_strategy)
        self.assertEqual('Trader-TESTER-000:Index:PositionStrategy', self.database.key_index_position_strategy)
        self.assertEqual('Trader-TESTER-000:Index:PositionOrders:', self.database.key_index_position_orders)
        self.assertEqual('Trader-TESTER-000:Index:StrategyOrders:', self.database.key_index_strategy_orders)
        self.assertEqual('Trader-TESTER-000:Index:StrategyPositions:', self.database.key_index_strategy_positions)
        self.assertEqual('Trader-TESTER-000:Index:Orders:Working', self.database.key_index_orders_working)
        self.assertEqual('Trader-TESTER-000:Index:Orders:Completed', self.database.key_index_orders_completed)
        self.assertEqual('Trader-TESTER-000:Index:Positions:Open', self.database.key_index_positions_open)
        self.assertEqual('Trader-TESTER-000:Index:Positions:Closed', self.database.key_index_positions_closed)

    def test_can_add_account(self):
        # Arrange
        event = TestStubs.account_event()
        account = Account(event)

        # Act
        self.database.add_account(account)

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

    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_account(self):
        # Arrange
        event = TestStubs.account_event()
        account = Account(event)
        self.database.add_account(account)

        # Act
        self.database.update_account(account)

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

    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_load_account_when_no_account_in_database_returns_none(self):
        # Arrange
        event = TestStubs.account_event()
        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.account_event()
        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_FXCM,
            OrderSide.BUY,
            Quantity(100000))

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

        # Assert
        self.assertIsNone(result)

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

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

        # Assert
        self.assertEqual(order, result)

    def test_load_position_when_no_position_in_database_returns_none(self):
        # Arrange
        position_id = self.strategy.position_id_generator.generate()

        # 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_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)

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

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

    def test_can_load_accounts_cache_when_no_accounts(self):
        # Arrange
        # Act
        self.database.load_accounts_cache()
        event = TestStubs.account_event()
        account = Account(event)

        # Assert
        self.assertIsNone(self.database.get_account(account.id))

    def test_can_load_accounts_cache_when_one_account_in_database(self):
        # Arrange
        event = TestStubs.account_event()
        account = Account(event)
        self.database.add_account(account)
        self.database.reset()

        # Act
        self.database.load_accounts_cache()

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

    def test_can_load_orders_cache_when_no_orders(self):
        # Arrange
        # Act
        self.database.load_orders_cache()

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

    def test_can_load_orders_cache_when_one_order_in_database(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)

        # Act
        self.database.load_orders_cache()

        # Assert
        self.assertEqual({order.id: order}, self.database.get_orders())

    def test_can_load_positions_cache_when_no_positions(self):
        # Arrange
        # Act
        self.database.load_positions_cache()

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

    def test_can_load_positions_cache_when_one_position_in_database(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)

        # Act
        self.database.load_positions_cache()

        # Assert
        self.assertEqual({position_id: position}, self.database.get_positions())

    def test_can_delete_strategy(self):
        # Arrange
        # 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_orders()))
        self.assertEqual(0, len(self.database.get_positions()))

    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_position_exists_for_order_when_no_position_returns_false(self):
        # Arrange
        # Act
        # Assert
        self.assertFalse(self.database.position_exists_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_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_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)