예제 #1
0
 def setUpClass(cls):
     cls.ev_loop: asyncio.BaseEventLoop = asyncio.get_event_loop()
     if API_MOCK_ENABLED:
         cls.web_app = HummingWebApp.get_instance()
         cls.web_app.add_host_to_mock(API_BASE_URL, ["/v1/common/timestamp", "/v1/common/symbols",
                                                     "/market/tickers", "/market/depth"])
         cls.web_app.start()
         cls.ev_loop.run_until_complete(cls.web_app.wait_til_started())
         cls._patcher = mock.patch("aiohttp.client.URL")
         cls._url_mock = cls._patcher.start()
         cls._url_mock.side_effect = cls.web_app.reroute_local
         mock_account_id = FixtureHuobi.GET_ACCOUNTS["data"][0]["id"]
         cls.web_app.update_response("get", API_BASE_URL, "/v1/account/accounts", FixtureHuobi.GET_ACCOUNTS)
         cls.web_app.update_response("get", API_BASE_URL, f"/v1/account/accounts/{mock_account_id}/balance",
                                     FixtureHuobi.GET_BALANCES)
         cls._t_nonce_patcher = unittest.mock.patch("hummingbot.market.huobi.huobi_market.get_tracking_nonce")
         cls._t_nonce_mock = cls._t_nonce_patcher.start()
     cls.clock: Clock = Clock(ClockMode.REALTIME)
     cls.market: HuobiMarket = HuobiMarket(
         API_KEY,
         API_SECRET,
         trading_pairs=["ethusdt"]
     )
     # Need 2nd instance of market to prevent events mixing up across tests
     cls.market_2: HuobiMarket = HuobiMarket(
         API_KEY,
         API_SECRET,
         trading_pairs=["ethusdt"]
     )
     cls.clock.add_iterator(cls.market)
     cls.clock.add_iterator(cls.market_2)
     cls.stack = contextlib.ExitStack()
     cls._clock = cls.stack.enter_context(cls.clock)
     cls.ev_loop.run_until_complete(cls.wait_til_ready())
 def setUpClass(cls):
     cls.clock: Clock = Clock(ClockMode.REALTIME)
     cls.market: HuobiMarket = HuobiMarket(conf.huobi_api_key,
                                           conf.huobi_secret_key,
                                           symbols=["ethusdt"])
     # Need 2nd instance of market to prevent events mixing up across tests
     cls.market_2: HuobiMarket = HuobiMarket(conf.huobi_api_key,
                                             conf.huobi_secret_key,
                                             symbols=["ethusdt"])
     cls.ev_loop: asyncio.BaseEventLoop = asyncio.get_event_loop()
     cls.clock.add_iterator(cls.market)
     cls.clock.add_iterator(cls.market_2)
     cls.stack = contextlib.ExitStack()
     cls._clock = cls.stack.enter_context(cls.clock)
     cls.ev_loop.run_until_complete(cls.wait_til_ready())
예제 #3
0
    async def fetch_huobi_trading_pairs(self) -> List[str]:
        try:
            from hummingbot.market.huobi.huobi_market import HuobiMarket

            client: aiohttp.ClientSession = self.http_client()
            async with client.get(HUOBI_ENDPOINT,
                                  timeout=API_CALL_TIMEOUT) as response:
                if response.status == 200:
                    all_trading_pairs: Dict[str, any] = await response.json()
                    valid_trading_pairs: list = []
                    for item in all_trading_pairs["data"]:
                        if item["state"] == "online":
                            valid_trading_pairs.append(item["symbol"])
                    trading_pair_list: List[str] = []
                    for raw_trading_pair in valid_trading_pairs:
                        converted_trading_pair: Optional[str] = \
                            HuobiMarket.convert_from_exchange_trading_pair(raw_trading_pair)
                        if converted_trading_pair is not None:
                            trading_pair_list.append(converted_trading_pair)
                        else:
                            self.logger().debug(
                                f"Could not parse the trading pair {raw_trading_pair}, skipping it..."
                            )
                    return trading_pair_list

        except Exception:
            # Do nothing if the request fails -- there will be no autocomplete for huobi trading pairs
            pass

        return []
예제 #4
0
    def connect_market(exchange, *api_details):
        market = None
        if exchange == "binance":
            market = BinanceMarket(api_details[0], api_details[1])
        elif exchange == "bittrex":
            market = BittrexMarket(api_details[0], api_details[1])
        elif exchange == "coinbase_pro":
            market = CoinbaseProMarket(api_details[0], api_details[1],
                                       api_details[2])
        elif exchange == "huobi":
            market = HuobiMarket(api_details[0], api_details[1])
        elif exchange == "kucoin":
            market = KucoinMarket(api_details[0], api_details[2],
                                  api_details[1])
        elif exchange == "liquid":
            market = LiquidMarket(api_details[0], api_details[1])
        elif exchange == "kraken":
            market = KrakenMarket(api_details[0], api_details[1])
        elif exchange == "beaxy":
            market = BeaxyMarket(api_details[0], api_details[1])
        elif exchange == "eterbase":
            market = EterbaseMarket(api_details[0], api_details[1],
                                    api_details[2])

        return market
예제 #5
0
    async def fetch_huobi_trading_pairs() -> List[str]:
        from hummingbot.market.huobi.huobi_market import HuobiMarket

        async with aiohttp.ClientSession() as client:
            async with client.get(HUOBI_ENDPOINT,
                                  timeout=API_CALL_TIMEOUT) as response:
                if response.status == 200:
                    try:
                        all_trading_pairs: Dict[str,
                                                any] = await response.json()
                        valid_trading_pairs: list = []
                        for item in all_trading_pairs["data"]:
                            if item["state"] == "online":
                                valid_trading_pairs.append(item["symbol"])
                        return [
                            HuobiMarket.convert_from_exchange_trading_pair(p)
                            for p in valid_trading_pairs
                        ]
                    except Exception:
                        pass
                        # Do nothing if the request fails -- there will be no autocomplete for huobi trading pairs
                return []
예제 #6
0
    def customSetUp(self):
        self.market: HuobiMarket = HuobiMarket(MOCK_HUOBI_API_KEY,
                                               MOCK_HUOBI_SECRET_KEY,
                                               symbols=["ethusdt"])

        # replace regular aiohttp client with test client
        self.market.shared_client: TestClient = self.client
        # replace default data source with mock data source
        mock_data_source: MockAPIOrderBookDataSource = MockAPIOrderBookDataSource(
            self.client, HuobiOrderBook, ["ethusdt"])
        self.market.order_book_tracker.data_source = mock_data_source

        self.clock.add_iterator(self.market)
        self.run_parallel(self.wait_til_ready(self.market, self._clock))
        self.db_path: str = realpath(join(__file__, "../huobi_test.sqlite"))
        try:
            os.unlink(self.db_path)
        except FileNotFoundError:
            pass

        self.market_logger = EventLogger()
        for event_tag in self.events:
            self.market.add_listener(event_tag, self.market_logger)
예제 #7
0
    def _initialize_markets(self, market_names: List[Tuple[str, List[str]]]):
        ethereum_rpc_url = global_config_map.get("ethereum_rpc_url").value

        # aggregate symbols if there are duplicate markets
        market_symbols_map = {}
        for market_name, symbols in market_names:
            if market_name not in market_symbols_map:
                market_symbols_map[market_name] = []
            market_symbols_map[market_name] += symbols

        for market_name, symbols in market_symbols_map.items():
            if global_config_map.get("paper_trade_enabled").value:
                self._notify(f"\nPaper trade is enabled for market {market_name}")
                try:
                    market = create_paper_trade_market(market_name, symbols)
                except Exception:
                    raise
                paper_trade_account_balance = global_config_map.get("paper_trade_account_balance").value
                for asset, balance in paper_trade_account_balance:
                    market.set_balance(asset, balance)

            elif market_name == "ddex" and self.wallet:
                market = DDEXMarket(wallet=self.wallet,
                                    ethereum_rpc_url=ethereum_rpc_url,
                                    order_book_tracker_data_source_type=OrderBookTrackerDataSourceType.EXCHANGE_API,
                                    symbols=symbols,
                                    trading_required=self._trading_required)

            elif market_name == "idex" and self.wallet:
                idex_api_key: str = global_config_map.get("idex_api_key").value
                try:
                    market = IDEXMarket(idex_api_key=idex_api_key,
                                        wallet=self.wallet,
                                        ethereum_rpc_url=ethereum_rpc_url,
                                        order_book_tracker_data_source_type=OrderBookTrackerDataSourceType.EXCHANGE_API,
                                        symbols=symbols,
                                        trading_required=self._trading_required)
                except Exception as e:
                    self.logger().error(str(e))

            elif market_name == "binance":
                binance_api_key = global_config_map.get("binance_api_key").value
                binance_api_secret = global_config_map.get("binance_api_secret").value
                market = BinanceMarket(binance_api_key,
                                       binance_api_secret,
                                       order_book_tracker_data_source_type=OrderBookTrackerDataSourceType.EXCHANGE_API,
                                       symbols=symbols,
                                       trading_required=self._trading_required)

            elif market_name == "radar_relay" and self.wallet:
                market = RadarRelayMarket(wallet=self.wallet,
                                          ethereum_rpc_url=ethereum_rpc_url,
                                          symbols=symbols,
                                          trading_required=self._trading_required)

            elif market_name == "bamboo_relay" and self.wallet:
                use_coordinator = global_config_map.get("bamboo_relay_use_coordinator").value
                pre_emptive_soft_cancels = global_config_map.get("bamboo_relay_pre_emptive_soft_cancels").value
                market = BambooRelayMarket(wallet=self.wallet,
                                           ethereum_rpc_url=ethereum_rpc_url,
                                           symbols=symbols,
                                           use_coordinator=use_coordinator,
                                           pre_emptive_soft_cancels=pre_emptive_soft_cancels,
                                           trading_required=self._trading_required)

            elif market_name == "coinbase_pro":
                coinbase_pro_api_key = global_config_map.get("coinbase_pro_api_key").value
                coinbase_pro_secret_key = global_config_map.get("coinbase_pro_secret_key").value
                coinbase_pro_passphrase = global_config_map.get("coinbase_pro_passphrase").value

                market = CoinbaseProMarket(coinbase_pro_api_key,
                                           coinbase_pro_secret_key,
                                           coinbase_pro_passphrase,
                                           symbols=symbols,
                                           trading_required=self._trading_required)
            elif market_name == "huobi":
                huobi_api_key = global_config_map.get("huobi_api_key").value
                huobi_secret_key = global_config_map.get("huobi_secret_key").value
                market = HuobiMarket(huobi_api_key,
                                     huobi_secret_key,
                                     order_book_tracker_data_source_type=OrderBookTrackerDataSourceType.EXCHANGE_API,
                                     symbols=symbols,
                                     trading_required=self._trading_required)
            else:
                raise ValueError(f"Market name {market_name} is invalid.")

            self.markets[market_name]: MarketBase = market

        self.markets_recorder = MarketsRecorder(
            self.trade_fill_db,
            list(self.markets.values()),
            in_memory_config_map.get("strategy_file_path").value,
            in_memory_config_map.get("strategy").value
        )
        self.markets_recorder.start()
예제 #8
0
    def _initialize_markets(self, market_names: List[Tuple[str, List[str]]]):
        ethereum_rpc_url = global_config_map.get("ethereum_rpc_url").value

        # aggregate trading_pairs if there are duplicate markets
        market_trading_pairs_map = {}
        for market_name, trading_pairs in market_names:
            if market_name not in market_trading_pairs_map:
                market_trading_pairs_map[market_name] = []
            market_class: MarketBase = MARKET_CLASSES.get(
                market_name, MarketBase)
            for trading_pair in trading_pairs:
                exchange_trading_pair: str = market_class.convert_to_exchange_trading_pair(
                    trading_pair)
                market_trading_pairs_map[market_name].append(
                    exchange_trading_pair)

        for market_name, trading_pairs in market_trading_pairs_map.items():
            if global_config_map.get("paper_trade_enabled").value:
                try:
                    market = create_paper_trade_market(market_name,
                                                       trading_pairs)
                except Exception:
                    raise
                paper_trade_account_balance = global_config_map.get(
                    "paper_trade_account_balance").value
                for asset, balance in paper_trade_account_balance.items():
                    market.set_balance(asset, balance)

            elif market_name == "binance":
                binance_api_key = global_config_map.get(
                    "binance_api_key").value
                binance_api_secret = global_config_map.get(
                    "binance_api_secret").value
                market = BinanceMarket(
                    binance_api_key,
                    binance_api_secret,
                    order_book_tracker_data_source_type=
                    OrderBookTrackerDataSourceType.EXCHANGE_API,
                    trading_pairs=trading_pairs,
                    trading_required=self._trading_required,
                )

            elif market_name == "radar_relay":
                assert self.wallet is not None
                market = RadarRelayMarket(
                    wallet=self.wallet,
                    ethereum_rpc_url=ethereum_rpc_url,
                    trading_pairs=trading_pairs,
                    trading_required=self._trading_required,
                )

            elif market_name == "bamboo_relay":
                assert self.wallet is not None
                use_coordinator = global_config_map.get(
                    "bamboo_relay_use_coordinator").value
                pre_emptive_soft_cancels = global_config_map.get(
                    "bamboo_relay_pre_emptive_soft_cancels").value
                market = BambooRelayMarket(
                    wallet=self.wallet,
                    ethereum_rpc_url=ethereum_rpc_url,
                    trading_pairs=trading_pairs,
                    use_coordinator=use_coordinator,
                    pre_emptive_soft_cancels=pre_emptive_soft_cancels,
                    trading_required=self._trading_required,
                )

            elif market_name == "coinbase_pro":
                coinbase_pro_api_key = global_config_map.get(
                    "coinbase_pro_api_key").value
                coinbase_pro_secret_key = global_config_map.get(
                    "coinbase_pro_secret_key").value
                coinbase_pro_passphrase = global_config_map.get(
                    "coinbase_pro_passphrase").value

                market = CoinbaseProMarket(
                    coinbase_pro_api_key,
                    coinbase_pro_secret_key,
                    coinbase_pro_passphrase,
                    trading_pairs=trading_pairs,
                    trading_required=self._trading_required)
            elif market_name == "huobi":
                huobi_api_key = global_config_map.get("huobi_api_key").value
                huobi_secret_key = global_config_map.get(
                    "huobi_secret_key").value
                market = HuobiMarket(
                    huobi_api_key,
                    huobi_secret_key,
                    order_book_tracker_data_source_type=
                    OrderBookTrackerDataSourceType.EXCHANGE_API,
                    trading_pairs=trading_pairs,
                    trading_required=self._trading_required)
            elif market_name == "liquid":
                liquid_api_key = global_config_map.get("liquid_api_key").value
                liquid_secret_key = global_config_map.get(
                    "liquid_secret_key").value

                market = LiquidMarket(
                    liquid_api_key,
                    liquid_secret_key,
                    order_book_tracker_data_source_type=
                    OrderBookTrackerDataSourceType.EXCHANGE_API,
                    user_stream_tracker_data_source_type=
                    UserStreamTrackerDataSourceType.EXCHANGE_API,
                    trading_pairs=trading_pairs,
                    trading_required=self._trading_required)
            elif market_name == "dolomite":
                assert self.wallet is not None
                is_test_net: bool = global_config_map.get(
                    "ethereum_chain_name").value == "DOLOMITE_TEST"
                market = DolomiteMarket(
                    wallet=self.wallet,
                    ethereum_rpc_url=ethereum_rpc_url,
                    order_book_tracker_data_source_type=
                    OrderBookTrackerDataSourceType.EXCHANGE_API,
                    trading_pairs=trading_pairs,
                    isTestNet=is_test_net,
                    trading_required=self._trading_required,
                )
            elif market_name == "bittrex":
                bittrex_api_key = global_config_map.get(
                    "bittrex_api_key").value
                bittrex_secret_key = global_config_map.get(
                    "bittrex_secret_key").value
                market = BittrexMarket(
                    bittrex_api_key,
                    bittrex_secret_key,
                    order_book_tracker_data_source_type=
                    OrderBookTrackerDataSourceType.EXCHANGE_API,
                    trading_pairs=trading_pairs,
                    trading_required=self._trading_required)
            elif market_name == "kucoin":
                kucoin_api_key = global_config_map.get("kucoin_api_key").value
                kucoin_secret_key = global_config_map.get(
                    "kucoin_secret_key").value
                kucoin_passphrase = global_config_map.get(
                    "kucoin_passphrase").value
                market = KucoinMarket(
                    kucoin_api_key,
                    kucoin_passphrase,
                    kucoin_secret_key,
                    order_book_tracker_data_source_type=
                    OrderBookTrackerDataSourceType.EXCHANGE_API,
                    trading_pairs=trading_pairs,
                    trading_required=self._trading_required)
            elif market_name == "eterbase":
                eterbase_api_key = global_config_map.get(
                    "eterbase_api_key").value
                eterbase_secret_key = global_config_map.get(
                    "eterbase_secret_key").value
                eterbase_account = global_config_map.get(
                    "eterbase_account").value
                market = EterbaseMarket(
                    eterbase_api_key,
                    eterbase_secret_key,
                    trading_pairs=trading_pairs,
                    trading_required=self._trading_required,
                    eterbase_account=eterbase_account)
            elif market_name == "kraken":
                kraken_api_key = global_config_map.get("kraken_api_key").value
                kraken_secret_key = global_config_map.get(
                    "kraken_secret_key").value
                market = KrakenMarket(
                    kraken_api_key,
                    kraken_secret_key,
                    order_book_tracker_data_source_type=
                    OrderBookTrackerDataSourceType.EXCHANGE_API,
                    trading_pairs=trading_pairs,
                    trading_required=self._trading_required)
            else:
                raise ValueError(f"Market name {market_name} is invalid.")

            self.markets[market_name]: MarketBase = market

        self.markets_recorder = MarketsRecorder(
            self.trade_fill_db,
            list(self.markets.values()),
            self.strategy_file_name,
            self.strategy_name,
        )
        self.markets_recorder.start()
예제 #9
0
    def test_orders_saving_and_restoration(self):
        self.customSetUp()
        config_path: str = "test_config"
        strategy_name: str = "test_strategy"
        symbol: str = "ethusdt"
        sql: SQLConnectionManager = SQLConnectionManager(
            SQLConnectionType.TRADE_FILLS, db_path=self.db_path)
        order_id: Optional[str] = None
        recorder: MarketsRecorder = MarketsRecorder(sql, [self.market],
                                                    config_path, strategy_name)
        recorder.start()

        try:
            self.assertEqual(0, len(self.market.tracking_states))

            # Try to put limit buy order for 0.04 ETH, and watch for order creation event.
            current_bid_price: Decimal = self.market.get_price(symbol, True)
            bid_price: Decimal = current_bid_price * Decimal(0.8)
            quantize_bid_price: Decimal = self.market.quantize_order_price(
                symbol, bid_price)

            amount: Decimal = Decimal(0.04)
            quantized_amount: Decimal = self.market.quantize_order_amount(
                symbol, amount)

            self.mock_api.order_id = self.mock_api.MOCK_HUOBI_LIMIT_OPEN_ORDER_ID
            order_id = self.market.buy(symbol, quantized_amount,
                                       OrderType.LIMIT, quantize_bid_price)
            [order_created_event] = self.run_parallel(
                self.market_logger.wait_for(BuyOrderCreatedEvent))
            order_created_event: BuyOrderCreatedEvent = order_created_event
            self.assertEqual(order_id, order_created_event.order_id)

            # Verify tracking states
            self.assertEqual(1, len(self.market.tracking_states))
            self.assertEqual(order_id,
                             list(self.market.tracking_states.keys())[0])

            # Verify orders from recorder
            recorded_orders: List[
                Order] = recorder.get_orders_for_config_and_market(
                    config_path, self.market)
            self.assertEqual(1, len(recorded_orders))
            self.assertEqual(order_id, recorded_orders[0].id)

            # Verify saved market states
            saved_market_states: MarketState = recorder.get_market_states(
                config_path, self.market)
            self.assertIsNotNone(saved_market_states)
            self.assertIsInstance(saved_market_states.saved_state, dict)
            self.assertGreater(len(saved_market_states.saved_state), 0)

            # Close out the current market and start another market.
            self.clock.remove_iterator(self.market)
            for event_tag in self.events:
                self.market.remove_listener(event_tag, self.market_logger)
            self.market: HuobiMarket = HuobiMarket(
                huobi_api_key=MOCK_HUOBI_API_KEY,
                huobi_secret_key=MOCK_HUOBI_SECRET_KEY,
                symbols=["ethusdt", "btcusdt"])
            self.market.shared_client: TestClient = self.client
            mock_data_source: MockAPIOrderBookDataSource = MockAPIOrderBookDataSource(
                self.client, HuobiOrderBook, ["ethusdt"])
            self.market.order_book_tracker.data_source = mock_data_source

            for event_tag in self.events:
                self.market.add_listener(event_tag, self.market_logger)
            recorder.stop()
            recorder = MarketsRecorder(sql, [self.market], config_path,
                                       strategy_name)
            recorder.start()
            saved_market_states = recorder.get_market_states(
                config_path, self.market)
            self.clock.add_iterator(self.market)
            self.assertEqual(0, len(self.market.limit_orders))
            self.assertEqual(0, len(self.market.tracking_states))
            self.market.restore_tracking_states(
                saved_market_states.saved_state)
            self.assertEqual(1, len(self.market.limit_orders))
            self.assertEqual(1, len(self.market.tracking_states))

            # Cancel the order and verify that the change is saved.
            self.mock_api.order_id = self.mock_api.MOCK_HUOBI_LIMIT_OPEN_ORDER_ID
            self.mock_api.order_response_dict[
                self.mock_api.
                MOCK_HUOBI_LIMIT_OPEN_ORDER_ID]["data"]["state"] = "canceled"
            self.market.cancel(symbol, order_id)
            self.run_parallel(self.market_logger.wait_for(OrderCancelledEvent))
            order_id = None
            self.assertEqual(0, len(self.market.limit_orders))
            self.assertEqual(0, len(self.market.tracking_states))
            saved_market_states = recorder.get_market_states(
                config_path, self.market)
            self.assertEqual(0, len(saved_market_states.saved_state))
        finally:
            if order_id is not None:
                self.market.cancel(symbol, order_id)
                self.run_parallel(
                    self.market_logger.wait_for(OrderCancelledEvent))

            recorder.stop()
            os.unlink(self.db_path)
예제 #10
0
    def test_orders_saving_and_restoration(self):
        config_path: str = "test_config"
        strategy_name: str = "test_strategy"
        symbol: str = "ethusdt"
        sql: SQLConnectionManager = SQLConnectionManager(
            SQLConnectionType.TRADE_FILLS, db_path=self.db_path)
        order_id: Optional[str] = None
        recorder: MarketsRecorder = MarketsRecorder(sql, [self.market],
                                                    config_path, strategy_name)
        recorder.start()

        try:
            self.assertEqual(0, len(self.market.tracking_states))

            # Try to put limit buy order for 0.04 ETH, and watch for order creation event.
            current_bid_price: float = self.market.get_price(symbol, True)
            bid_price: float = current_bid_price * 0.8
            quantize_bid_price: Decimal = self.market.quantize_order_price(
                symbol, bid_price)

            amount: float = 0.04
            quantized_amount: Decimal = self.market.quantize_order_amount(
                symbol, amount)

            order_id = self.market.buy(symbol, quantized_amount,
                                       OrderType.LIMIT, quantize_bid_price)
            [order_created_event] = self.run_parallel(
                self.market_logger.wait_for(BuyOrderCreatedEvent))
            order_created_event: BuyOrderCreatedEvent = order_created_event
            self.assertEqual(order_id, order_created_event.order_id)

            # Verify tracking states
            self.assertEqual(1, len(self.market.tracking_states))
            self.assertEqual(order_id,
                             list(self.market.tracking_states.keys())[0])

            # Verify orders from recorder
            recorded_orders: List[
                Order] = recorder.get_orders_for_config_and_market(
                    config_path, self.market)
            self.assertEqual(1, len(recorded_orders))
            self.assertEqual(order_id, recorded_orders[0].id)

            # Verify saved market states
            saved_market_states: MarketState = recorder.get_market_states(
                config_path, self.market)
            self.assertIsNotNone(saved_market_states)
            self.assertIsInstance(saved_market_states.saved_state, dict)
            self.assertGreater(len(saved_market_states.saved_state), 0)

            # Close out the current market and start another market.
            self.clock.remove_iterator(self.market)
            for event_tag in self.events:
                self.market.remove_listener(event_tag, self.market_logger)
            self.market: HuobiMarket = HuobiMarket(
                huobi_api_key=conf.huobi_api_key,
                huobi_secret_key=conf.huobi_secret_key,
                symbols=["ethusdt", "btcusdt"])
            for event_tag in self.events:
                self.market.add_listener(event_tag, self.market_logger)
            recorder.stop()
            recorder = MarketsRecorder(sql, [self.market], config_path,
                                       strategy_name)
            recorder.start()
            saved_market_states = recorder.get_market_states(
                config_path, self.market)
            self.clock.add_iterator(self.market)
            self.assertEqual(0, len(self.market.limit_orders))
            self.assertEqual(0, len(self.market.tracking_states))
            self.market.restore_tracking_states(
                saved_market_states.saved_state)
            self.assertEqual(1, len(self.market.limit_orders))
            self.assertEqual(1, len(self.market.tracking_states))

            # Cancel the order and verify that the change is saved.
            self.market.cancel(symbol, order_id)
            self.run_parallel(self.market_logger.wait_for(OrderCancelledEvent))
            order_id = None
            self.assertEqual(0, len(self.market.limit_orders))
            self.assertEqual(0, len(self.market.tracking_states))
            saved_market_states = recorder.get_market_states(
                config_path, self.market)
            self.assertEqual(0, len(saved_market_states.saved_state))
        finally:
            if order_id is not None:
                self.market.cancel(symbol, order_id)
                self.run_parallel(
                    self.market_logger.wait_for(OrderCancelledEvent))

            recorder.stop()
            os.unlink(self.db_path)