def test_filled_orders_recorded(self): config_path: str = "test_config" strategy_name: str = "test_strategy" sql = SQLConnectionManager(SQLConnectionType.TRADE_FILLS, db_path=self.db_path) order_id = None recorder = MarketsRecorder(sql, [self.connector], config_path, strategy_name) recorder.start() try: # Try to buy some token from the exchange, and watch for completion event. price = self.connector.get_price(self.trading_pair, True) * Decimal("1.05") price = self.connector.quantize_order_price( self.trading_pair, price) amount = self.connector.quantize_order_amount( self.trading_pair, Decimal("0.0001")) order_id = self._place_order(True, amount, OrderType.LIMIT, price, 1, None, fixture.WS_TRADE) self.ev_loop.run_until_complete( self.event_logger.wait_for(BuyOrderCompletedEvent)) self.ev_loop.run_until_complete(asyncio.sleep(1)) # Reset the logs self.event_logger.clear() # Try to sell back the same amount to the exchange, and watch for completion event. price = self.connector.get_price(self.trading_pair, True) * Decimal("0.95") price = self.connector.quantize_order_price( self.trading_pair, price) amount = self.connector.quantize_order_amount( self.trading_pair, Decimal("0.0001")) order_id = self._place_order(False, amount, OrderType.LIMIT, price, 2, None, fixture.WS_TRADE) self.ev_loop.run_until_complete( self.event_logger.wait_for(SellOrderCompletedEvent)) # Query the persisted trade logs trade_fills: List[TradeFill] = recorder.get_trades_for_config( config_path) self.assertGreaterEqual(len(trade_fills), 2) buy_fills: List[TradeFill] = [ t for t in trade_fills if t.trade_type == "BUY" ] sell_fills: List[TradeFill] = [ t for t in trade_fills if t.trade_type == "SELL" ] self.assertGreaterEqual(len(buy_fills), 1) self.assertGreaterEqual(len(sell_fills), 1) order_id = None finally: if order_id is not None: self.connector.cancel(self.trading_pair, order_id) self.run_parallel( self.event_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def strategy_file_name(self, value: str): self._strategy_file_name = value db_name = value.split(".")[0] self.trade_fill_db = SQLConnectionManager.get_trade_fills_instance( db_name=db_name)
def test_orders_saving_and_restoration(self): self.tearDownClass() self.setUpClass() self.setUp() config_path: str = "test_config" strategy_name: str = "test_strategy" 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)) amount: Decimal = Decimal("0.04") current_ask_price: Decimal = self.market.get_price( trading_pair, False) bid_price: Decimal = Decimal("0.9") * current_ask_price quantize_ask_price: Decimal = self.market.quantize_order_price( trading_pair, bid_price) order_id = self.market.buy(trading_pair, amount, OrderType.LIMIT, quantize_ask_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: BitfinexExchange = BitfinexExchange( API_KEY, API_SECRET, trading_pairs=[trading_pair]) 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.run_parallel(asyncio.sleep(5.0)) self.market.cancel(trading_pair, 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(trading_pair, order_id) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() self.setUpClass()
def test_orders_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" trading_pair: str = "ETH-USDT" 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( trading_pair, True) bid_price: Decimal = Decimal(current_bid_price * Decimal(0.8)) quantize_bid_price: Decimal = self.market.quantize_order_price( trading_pair, bid_price) amount: Decimal = Decimal(0.04) quantized_amount: Decimal = self.market.quantize_order_amount( trading_pair, amount) order_id, exch_order_id = self.place_order( True, trading_pair, quantized_amount, OrderType.LIMIT_MAKER, quantize_bid_price, 10001, FixtureKucoin.ORDER_PLACE, FixtureKucoin.OPEN_BUY_LIMIT_ORDER) [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: KucoinMarket = KucoinMarket( kucoin_api_key=API_KEY, kucoin_passphrase=API_PASSPHRASE, kucoin_secret_key=API_SECRET, trading_pairs=["ETH-USDT"]) 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)) if API_MOCK_ENABLED: resp = FixtureKucoin.CANCEL_ORDER.copy() resp["data"]["cancelledOrderIds"] = exch_order_id self.web_app.update_response( "delete", API_BASE_URL, f"/api/v1/orders/{exch_order_id}", resp) # Cancel the order and verify that the change is saved. self.market.cancel(trading_pair, order_id) if API_MOCK_ENABLED: resp = FixtureKucoin.GET_CANCELLED_ORDER.copy() resp["data"]["id"] = exch_order_id resp["data"]["clientOid"] = order_id self.web_app.update_response( "get", API_BASE_URL, f"/api/v1/orders/{exch_order_id}", resp) 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(trading_pair, order_id) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path) self.market_logger.clear()
def test_orders_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" trading_pair: str = "ETH-USDT" 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(trading_pair, True) bid_price: Decimal = current_bid_price * Decimal("0.8") quantize_bid_price: Decimal = self.market.quantize_order_price(trading_pair, bid_price) amount: Decimal = Decimal("0.06") quantized_amount: Decimal = self.market.quantize_order_amount(trading_pair, amount) order_id, exch_order_id = self.place_order(True, trading_pair, quantized_amount, OrderType.LIMIT_MAKER, quantize_bid_price, 10001, FixtureMEXC.ORDER_GET_LIMIT_BUY_UNFILLED) [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: MexcExchange = MexcExchange( API_KEY, API_SECRET, trading_pairs=["ETH-USDT"] ) 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.cancel_order(trading_pair, order_id, exch_order_id, FixtureMEXC.ORDER_GET_CANCELED) # saved_market_states2 = recorder.get_market_states(config_path, self.market) self.run_parallel(self.market_logger.wait_for(OrderCancelledEvent)) # saved_market_states3 = recorder.get_market_states(config_path, self.market) 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(trading_pair, order_id) self.run_parallel(self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def test_orders_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" 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.005 ETH worth of CEL, and watch for order creation event. current_bid_price: Decimal = self.market.get_price("CEL-ETH", True) bid_price: Decimal = current_bid_price * Decimal("0.8") quantize_bid_price: Decimal = self.market.quantize_order_price( "CEL-ETH", bid_price) amount: Decimal = 1 quantized_amount: Decimal = self.market.quantize_order_amount( "CEL-ETH", amount) order_id, buy_exchange_id = self.place_order( True, "CEL-ETH", quantized_amount, OrderType.LIMIT, quantize_bid_price, 10001, FixtureLiquid.ORDER_SAVE_RESTORE, FixtureLiquid.ORDERS_GET_AFTER_BUY) [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: LiquidMarket = LiquidMarket( API_KEY, API_SECRET, order_book_tracker_data_source_type= OrderBookTrackerDataSourceType.EXCHANGE_API, user_stream_tracker_data_source_type= UserStreamTrackerDataSourceType.EXCHANGE_API, trading_pairs=['ETH-USD', 'CEL-ETH']) 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. if API_MOCK_ENABLED: order_cancel_resp = FixtureLiquid.ORDER_CANCEL_SAVE_RESTORE.copy( ) self.web_app.update_response( "put", API_HOST, f"/orders/{str(buy_exchange_id)}/cancel", order_cancel_resp) self.market.cancel("CEL-ETH", 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("CEL-ETH", order_id) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def test_orders_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" trading_pair: str = "ETH-USDT" 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)) current_bid_price: Decimal = self.market.get_price( trading_pair, True) * Decimal('0.80') quantize_bid_price: Decimal = self.market.quantize_order_price( trading_pair, current_bid_price) bid_amount: Decimal = Decimal('0.06') quantized_bid_amount: Decimal = self.market.quantize_order_amount( trading_pair, bid_amount) order_id, exch_order_id = self.place_order( True, trading_pair, quantized_bid_amount, OrderType.LIMIT, quantize_bid_price, 10001, FixtureBittrex.ORDER_PLACE_OPEN, FixtureBittrex.WS_ORDER_OPEN) [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: BittrexMarket = BittrexMarket( bittrex_api_key=API_KEY, bittrex_secret_key=API_SECRET, trading_pairs=["XRP-BTC"]) 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.cancel_order(trading_pair, order_id, exch_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(trading_pair, order_id) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def test_orders_saving_and_restoration(self): config_path = "test_config" strategy_name = "test_strategy" sql = SQLConnectionManager(SQLConnectionType.TRADE_FILLS, db_path=self.db_path) order_id = None recorder = MarketsRecorder(sql, [self.connector], config_path, strategy_name) recorder.start() try: self.connector._in_flight_orders.clear() self.assertEqual(0, len(self.connector.tracking_states)) # Try to put limit buy order for 0.02 ETH worth of ZRX, and watch for order creation event. current_bid_price: Decimal = self.connector.get_price(self.trading_pair, True) price: Decimal = current_bid_price * Decimal("0.8") price = self.connector.quantize_order_price(self.trading_pair, price) amount: Decimal = self.order_amount amount = self.connector.quantize_order_amount(self.trading_pair, amount) cl_order_id = self._place_order(True, amount, OrderType.LIMIT_MAKER, price, 1) order_created_event = self.ev_loop.run_until_complete(self.event_logger.wait_for(BuyOrderCreatedEvent)) self.assertEqual(cl_order_id, order_created_event.order_id) # Verify tracking states self.assertEqual(1, len(self.connector.tracking_states)) self.assertEqual(cl_order_id, list(self.connector.tracking_states.keys())[0]) # Verify orders from recorder recorded_orders: List[Order] = recorder.get_orders_for_config_and_market(config_path, self.connector) self.assertEqual(1, len(recorded_orders)) self.assertEqual(cl_order_id, recorded_orders[0].id) # Verify saved market states saved_market_states: MarketState = recorder.get_market_states(config_path, self.connector) 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.connector.stop(self._clock) self.ev_loop.run_until_complete(asyncio.sleep(5)) self.clock.remove_iterator(self.connector) for event_tag in self.events: self.connector.remove_listener(event_tag, self.event_logger) # Clear the event loop self.event_logger.clear() new_connector = GateIoExchange(API_KEY, API_SECRET, [self.trading_pair], True) for event_tag in self.events: new_connector.add_listener(event_tag, self.event_logger) recorder.stop() recorder = MarketsRecorder(sql, [new_connector], config_path, strategy_name) recorder.start() saved_market_states = recorder.get_market_states(config_path, new_connector) self.clock.add_iterator(new_connector) self.ev_loop.run_until_complete(self.wait_til_ready(new_connector)) self.assertEqual(0, len(new_connector.limit_orders)) self.assertEqual(0, len(new_connector.tracking_states)) new_connector.restore_tracking_states(saved_market_states.saved_state) self.assertEqual(1, len(new_connector.limit_orders)) self.assertEqual(1, len(new_connector.tracking_states)) # Cancel the order and verify that the change is saved. self._cancel_order(cl_order_id, new_connector) self.ev_loop.run_until_complete(self.event_logger.wait_for(OrderCancelledEvent)) recorder.save_market_states(config_path, new_connector) order_id = None self.assertEqual(0, len(new_connector.limit_orders)) self.assertEqual(0, len(new_connector.tracking_states)) saved_market_states = recorder.get_market_states(config_path, new_connector) self.assertEqual(0, len(saved_market_states.saved_state)) finally: if order_id is not None: self.connector.cancel(self.trading_pair, cl_order_id) self.run_parallel(self.event_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def setUpClass(cls): cls.trade_fill_sql = SQLConnectionManager( SQLConnectionType.TRADE_FILLS, db_path="") cls.trading_pair = "BTC-USDT" cls.base_asset, cls.quote_asset = cls.trading_pair.split("-") cls._session = cls.trade_fill_sql.get_shared_session()
def test_filled_orders_recorded(self): config_path = "test_config" strategy_name = "test_strategy" sql = SQLConnectionManager(SQLConnectionType.TRADE_FILLS, db_path=self.db_path) recorder = MarketsRecorder(sql, [self.connector], config_path, strategy_name) recorder.start() try: self.connector._in_flight_orders.clear() self.assertEqual(0, len(self.connector.tracking_states)) price: Decimal = Decimal("10") # quote_price * Decimal("0.8") price = self.connector.quantize_order_price(trading_pair, price) amount: Decimal = Decimal("0.1") amount = self.connector.quantize_order_amount(trading_pair, amount) sell_order_id = self.connector.sell( trading_pair, amount, OrderType.LIMIT, price, position_action=PositionAction.OPEN) self.ev_loop.run_until_complete( self.event_logger.wait_for(SellOrderCompletedEvent)) self.ev_loop.run_until_complete(asyncio.sleep(1)) price: Decimal = Decimal("10") # quote_price * Decimal("0.8") price = self.connector.quantize_order_price(trading_pair, price) buy_order_id = self.connector.buy( trading_pair, amount, OrderType.LIMIT, price, position_action=PositionAction.CLOSE) self.ev_loop.run_until_complete( self.event_logger.wait_for(BuyOrderCompletedEvent)) self.ev_loop.run_until_complete(asyncio.sleep(1)) # Query the persisted trade logs trade_fills: List[TradeFill] = recorder.get_trades_for_config( config_path) # self.assertGreaterEqual(len(trade_fills), 2) fills: List[TradeFill] = [ t for t in trade_fills if t.trade_type == "SELL" ] self.assertGreaterEqual(len(fills), 1) self.assertEqual(amount, Decimal(str(fills[0].amount))) # self.assertEqual(price, Decimal(str(fills[0].price))) self.assertEqual(base, fills[0].base_asset) self.assertEqual(quote, fills[0].quote_asset) self.assertEqual(sell_order_id, fills[0].order_id) self.assertEqual(trading_pair, fills[0].symbol) fills: List[TradeFill] = [ t for t in trade_fills if t.trade_type == "BUY" ] self.assertGreaterEqual(len(fills), 1) self.assertEqual(amount, Decimal(str(fills[0].amount))) # self.assertEqual(price, Decimal(str(fills[0].price))) self.assertEqual(base, fills[0].base_asset) self.assertEqual(quote, fills[0].quote_asset) self.assertEqual(buy_order_id, fills[0].order_id) self.assertEqual(trading_pair, fills[0].symbol) finally: recorder.stop() os.unlink(self.db_path)
class MarketsRecorderTests(TestCase): @patch( "hummingbot.model.sql_connection_manager.SQLConnectionManager.get_db_engine" ) def setUp(self, engine_mock) -> None: super().setUp() self.display_name = "test_market" self.config_file_path = "test_config" self.strategy_name = "test_strategy" self.symbol = "COINALPHAHBOT" self.base = "COINALPHA" self.quote = "HBOT" self.trading_pair = f"{self.base}-{self.quote}" engine_mock.return_value = create_engine("sqlite:///:memory:") self.manager = SQLConnectionManager(SQLConnectionType.TRADE_FILLS, db_name="test_DB") self.tracking_states = dict() def add_trade_fills_from_market_recorder(self, current_trade_fills): pass def add_exchange_order_ids_from_market_recorder( self, current_exchange_order_ids): pass def test_properties(self): recorder = MarketsRecorder(sql=self.manager, markets=[self], config_file_path=self.config_file_path, strategy_name=self.strategy_name) self.assertEqual(self.manager, recorder.sql_manager) self.assertEqual(self.config_file_path, recorder.config_file_path) self.assertEqual(self.strategy_name, recorder.strategy_name) def test_get_trade_for_config(self): recorder = MarketsRecorder(sql=self.manager, markets=[self], config_file_path=self.config_file_path, strategy_name=self.strategy_name) with self.manager.get_new_session() as session: with session.begin(): trade_fill_record = TradeFill( config_file_path=self.config_file_path, strategy=self.strategy_name, market=self.display_name, symbol=self.symbol, base_asset=self.base, quote_asset=self.quote, timestamp=int(time.time()), order_id="OID1", trade_type=TradeType.BUY.name, order_type=OrderType.LIMIT.name, price=Decimal(1000), amount=Decimal(1), leverage=1, trade_fee=AddedToCostTradeFee().to_json(), exchange_trade_id="EOID1", position=PositionAction.NIL.value) session.add(trade_fill_record) fill_id = trade_fill_record.exchange_trade_id trades = recorder.get_trades_for_config("test_config") self.assertEqual(1, len(trades)) self.assertEqual(fill_id, trades[0].exchange_trade_id) def test_buy_order_created_event_creates_order_record(self): recorder = MarketsRecorder(sql=self.manager, markets=[self], config_file_path=self.config_file_path, strategy_name=self.strategy_name) event = BuyOrderCreatedEvent( timestamp=int(time.time()), type=OrderType.LIMIT, trading_pair=self.trading_pair, amount=Decimal(1), price=Decimal(1000), order_id="OID1", creation_timestamp=1640001112.223, exchange_order_id="EOID1", ) recorder._did_create_order(MarketEvent.BuyOrderCreated.value, self, event) with self.manager.get_new_session() as session: query = session.query(Order) orders = query.all() order = orders[0] order_status = order.status trade_fills = order.trade_fills self.assertEqual(1, len(orders)) self.assertEqual(self.config_file_path, orders[0].config_file_path) self.assertEqual(event.order_id, orders[0].id) self.assertEqual(1640001112223, orders[0].creation_timestamp) self.assertEqual(1, len(order_status)) self.assertEqual(MarketEvent.BuyOrderCreated.name, order_status[0].status) self.assertEqual(0, len(trade_fills)) def test_sell_order_created_event_creates_order_record(self): recorder = MarketsRecorder(sql=self.manager, markets=[self], config_file_path=self.config_file_path, strategy_name=self.strategy_name) event = SellOrderCreatedEvent( timestamp=int(time.time()), type=OrderType.LIMIT, trading_pair=self.trading_pair, amount=Decimal(1), price=Decimal(1000), order_id="OID1", creation_timestamp=1640001112.223, exchange_order_id="EOID1", ) recorder._did_create_order(MarketEvent.SellOrderCreated.value, self, event) with self.manager.get_new_session() as session: query = session.query(Order) orders = query.all() order = orders[0] order_status = order.status trade_fills = order.trade_fills self.assertEqual(1, len(orders)) self.assertEqual(self.config_file_path, orders[0].config_file_path) self.assertEqual(event.order_id, orders[0].id) self.assertEqual(1640001112223, orders[0].creation_timestamp) self.assertEqual(1, len(order_status)) self.assertEqual(MarketEvent.SellOrderCreated.name, order_status[0].status) self.assertEqual(0, len(trade_fills)) def test_create_order_and_process_fill(self): recorder = MarketsRecorder(sql=self.manager, markets=[self], config_file_path=self.config_file_path, strategy_name=self.strategy_name) create_event = BuyOrderCreatedEvent( timestamp=1642010000, type=OrderType.LIMIT, trading_pair=self.trading_pair, amount=Decimal(1), price=Decimal(1000), order_id="OID1-1642010000000000", creation_timestamp=1640001112.223, exchange_order_id="EOID1", ) recorder._did_create_order(MarketEvent.BuyOrderCreated.value, self, create_event) fill_event = OrderFilledEvent(timestamp=1642020000, order_id=create_event.order_id, trading_pair=create_event.trading_pair, trade_type=TradeType.BUY, order_type=create_event.type, price=Decimal(1010), amount=create_event.amount, trade_fee=AddedToCostTradeFee(), exchange_trade_id="TradeId1") recorder._did_fill_order(MarketEvent.OrderFilled.value, self, fill_event) with self.manager.get_new_session() as session: query = session.query(Order) orders = query.all() order = orders[0] order_status = order.status trade_fills = order.trade_fills self.assertEqual(1, len(orders)) self.assertEqual(self.config_file_path, orders[0].config_file_path) self.assertEqual(create_event.order_id, orders[0].id) self.assertEqual(2, len(order_status)) self.assertEqual(MarketEvent.BuyOrderCreated.name, order_status[0].status) self.assertEqual(MarketEvent.OrderFilled.name, order_status[1].status) self.assertEqual(1, len(trade_fills)) self.assertEqual(self.config_file_path, trade_fills[0].config_file_path) self.assertEqual(fill_event.order_id, trade_fills[0].order_id) def test_create_order_and_completed(self): recorder = MarketsRecorder(sql=self.manager, markets=[self], config_file_path=self.config_file_path, strategy_name=self.strategy_name) create_event = BuyOrderCreatedEvent( timestamp=1642010000, type=OrderType.LIMIT, trading_pair=self.trading_pair, amount=Decimal(1), price=Decimal(1000), order_id="OID1-1642010000000000", creation_timestamp=1640001112.223, exchange_order_id="EOID1", ) recorder._did_create_order(MarketEvent.BuyOrderCreated.value, self, create_event) complete_event = BuyOrderCompletedEvent( timestamp=1642020000, order_id=create_event.order_id, base_asset=self.base, quote_asset=self.quote, base_asset_amount=create_event.amount, quote_asset_amount=create_event.amount * create_event.price, order_type=create_event.type) recorder._did_complete_order(MarketEvent.BuyOrderCompleted.value, self, complete_event) with self.manager.get_new_session() as session: query = session.query(Order) orders = query.all() order = orders[0] order_status = order.status trade_fills = order.trade_fills self.assertEqual(1, len(orders)) self.assertEqual(self.config_file_path, orders[0].config_file_path) self.assertEqual(create_event.order_id, orders[0].id) self.assertEqual(2, len(order_status)) self.assertEqual(MarketEvent.BuyOrderCreated.name, order_status[0].status) self.assertEqual(MarketEvent.BuyOrderCompleted.name, order_status[1].status) self.assertEqual(0, len(trade_fills))
def __init__(self, sql: SQLConnectionManager, trading_pair: str) -> None: self.base_asset, self.quote_asset = trading_pair.split("-") self._session = sql.get_shared_session()
def test_orders_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" 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.02 ETH worth of ZRX, and watch for order creation event. current_bid_price: Decimal = self.market.get_price("ZRXETH", True) bid_price: Decimal = current_bid_price * Decimal("0.8") quantize_bid_price: Decimal = self.market.quantize_order_price("ZRXETH", bid_price) amount: Decimal = Decimal("0.02") / bid_price quantized_amount: Decimal = self.market.quantize_order_amount("ZRXETH", amount) order_id = self.market.buy("ZRXETH", 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: BinanceMarket = BinanceMarket( binance_api_key=conf.binance_api_key, binance_api_secret=conf.binance_api_secret, order_book_tracker_data_source_type=OrderBookTrackerDataSourceType.EXCHANGE_API, user_stream_tracker_data_source_type=UserStreamTrackerDataSourceType.EXCHANGE_API, symbols=["ZRXETH", "IOSTETH"] ) 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("ZRXETH", 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("ZRXETH", order_id) self.run_parallel(self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def test_orders_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" symbol: str = ETH_QNT 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.05 ETH worth of QNT, and watch for order creation event. bid_price = Decimal("0.00000002") quantize_bid_price: Decimal = self.market.quantize_order_price( symbol, bid_price) amount: Decimal = Decimal("18000000") quantized_amount: Decimal = self.market.quantize_order_amount( symbol, amount) expires = int(time.time() + 60 * 5) order_id = self.market.buy(symbol, quantized_amount, OrderType.LIMIT, quantize_bid_price, expiration_ts=expires) [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.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.market_events: self.market.remove_listener(event_tag, self.market_logger) self.market: IDEXMarket = IDEXMarket( idex_api_key=conf.idex_api_key, wallet=self.wallet, ethereum_rpc_url=conf.test_web3_provider_list[0], order_book_tracker_data_source_type= OrderBookTrackerDataSourceType.EXCHANGE_API, symbols=[ETH_QNT]) for event_tag in self.market_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(1, len(self.market.tracking_states)) saved_market_states = recorder.get_market_states( config_path, self.market) self.assertEqual(1, 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)
def test_order_fill_record(self): config_path: str = "test_config" strategy_name: str = "test_strategy" trading_pair: str = "ETHEUR" 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: # Try to buy 0.04 ETH from the exchange, and watch for completion event. amount: Decimal = Decimal("0.01") current_ask_price: Decimal = self.market.get_price( trading_pair, False) ask_price: Decimal = current_ask_price - Decimal( "0.05") * current_ask_price quantize_price: Decimal = self.market.quantize_order_price( trading_pair, ask_price) order_id = self.market.buy(trading_pair, amount, OrderType.MARKET, quantize_price) [buy_order_completed_event] = self.run_parallel( self.market_logger.wait_for(BuyOrderCompletedEvent)) # Reset the logger self.market_logger.clear() # Try to sell back the same amount of ETH to the exchange, and watch for completion event. amount = buy_order_completed_event.base_asset_amount order_id = self.market.sell(trading_pair, amount) [sell_order_completed_event] = self.run_parallel( self.market_logger.wait_for(SellOrderCompletedEvent)) # Query the persisted trade logs trade_fills: List[TradeFill] = recorder.get_trades_for_config( config_path) self.assertEqual(2, len(trade_fills)) buy_fills: List[TradeFill] = [ t for t in trade_fills if t.trade_type == "BUY" ] sell_fills: List[TradeFill] = [ t for t in trade_fills if t.trade_type == "SELL" ] self.assertEqual(1, len(buy_fills)) self.assertEqual(1, len(sell_fills)) order_id = None finally: if order_id is not None: self.market.cancel(trading_pair, order_id) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def test_order_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" 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.02 ETH at fraction of USDC market price, and watch for order creation event. order_id = self.underpriced_limit_buy() [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: KrakenExchange = KrakenExchange( conf.kraken_api_key, conf.kraken_secret_key, trading_pairs=[PAIR] ) 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(PAIR, 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(PAIR, order_id) self.run_parallel(self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() unlink(self.db_path)
def test_orders_saving_and_restoration(self): self.customSetUp() config_path: str = "test_config" strategy_name: str = "test_strategy" trading_pair: 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( trading_pair, True) bid_price: Decimal = current_bid_price * Decimal(0.8) quantize_bid_price: Decimal = self.market.quantize_order_price( trading_pair, bid_price) amount: Decimal = Decimal(0.04) quantized_amount: Decimal = self.market.quantize_order_amount( trading_pair, amount) self.mock_api.order_id = self.mock_api.MOCK_HUOBI_LIMIT_OPEN_ORDER_ID order_id = self.market.buy(trading_pair, quantized_amount, OrderType.LIMIT_MAKER, 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, trading_pairs=["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(trading_pair, 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(trading_pair, order_id) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def test_orders_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" trading_pair: str = "ZRX-WETH" 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["limit_orders"])) # Try to put limit buy order for 0.05 ETH worth of ZRX, and watch for order creation event. current_bid_price: Decimal = self.market.get_price( trading_pair, True) bid_price: Decimal = current_bid_price * Decimal(0.8) quantize_bid_price: Decimal = self.market.quantize_order_price( trading_pair, bid_price) amount: float = Decimal("0.05") / bid_price quantized_amount: Decimal = self.market.quantize_order_amount( trading_pair, Decimal(amount)) expires = int(time.time() + 60 * 5) order_id = self.market.buy(trading_pair, quantized_amount, OrderType.LIMIT, quantize_bid_price, expiration_ts=expires) [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["limit_orders"])) self.assertEqual( order_id, list(self.market.tracking_states["limit_orders"].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.assertIsInstance( saved_market_states.saved_state["limit_orders"], dict) self.assertGreater( len(saved_market_states.saved_state["limit_orders"]), 0) # Close out the current market and start another market. self.clock.remove_iterator(self.market) for event_tag in self.market_events: self.market.remove_listener(event_tag, self.market_logger) self.market = RadarRelayExchange( wallet=self.wallet, ethereum_rpc_url=conf.test_web3_provider_list[0], trading_pairs=["ZRX-WETH"]) for event_tag in self.market_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["limit_orders"])) 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["limit_orders"])) # Cancel the order and verify that the change is saved. self.market.cancel(trading_pair, order_id) self.run_parallel(self.market_logger.wait_for(OrderCancelledEvent)) order_id = None self.assertEqual(0, len(self.market.limit_orders)) self.assertEqual(1, len(self.market.tracking_states["limit_orders"])) saved_market_states = recorder.get_market_states( config_path, self.market) self.assertEqual( 1, len(saved_market_states.saved_state["limit_orders"])) finally: if order_id is not None: self.market.cancel(trading_pair, order_id) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def test_z_orders_saving_and_restoration(self): self.market.reset_state() config_path: str = "test_config" strategy_name: str = "test_strategy" trading_pair: str = self.base_token_asset + "-" + self.quote_token_asset 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["limit_orders"])) # Try to put limit buy order for 0.05 Quote Token worth of Base Token, and watch for order creation event. current_bid_price: Decimal = self.market.get_price( trading_pair, True) bid_price: Decimal = current_bid_price * Decimal("0.8") quantize_bid_price: Decimal = self.market.quantize_order_price( trading_pair, bid_price) amount: Decimal = Decimal("0.005") / bid_price quantized_amount: Decimal = self.market.quantize_order_amount( trading_pair, amount) expires = int(time.time() + 60 * 3) order_id = self.market.buy(trading_pair, quantized_amount, OrderType.LIMIT, quantize_bid_price, expiration_ts=expires) [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["limit_orders"])) self.assertEqual( order_id, list(self.market.tracking_states["limit_orders"].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.assertIsInstance( saved_market_states.saved_state["limit_orders"], dict) self.assertGreater( len(saved_market_states.saved_state["limit_orders"]), 0) # Close out the current market and start another market. self.clock.remove_iterator(self.market) for event_tag in self.market_events: self.market.remove_listener(event_tag, self.market_logger) self.market: BambooRelayMarket = BambooRelayMarket( wallet=self.wallet, ethereum_rpc_url=conf.test_web3_provider_list[0], order_book_tracker_data_source_type= OrderBookTrackerDataSourceType.EXCHANGE_API, trading_pairs=[ self.base_token_asset + "-" + self.quote_token_asset ], use_coordinator=False, pre_emptive_soft_cancels=False) for event_tag in self.market_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["limit_orders"])) 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["limit_orders"])) # Cancel the order and verify that the change is saved. self.run_parallel(self.market.cancel(trading_pair, order_id), self.market_logger.wait_for(OrderCancelledEvent)) order_id = None self.assertEqual(0, len(self.market.limit_orders)) self.assertEqual(1, len(self.market.tracking_states["limit_orders"])) saved_market_states = recorder.get_market_states( config_path, self.market) self.assertEqual( 1, len(saved_market_states.saved_state["limit_orders"])) finally: if order_id is not None: self.run_parallel( self.market.cancel(trading_pair, order_id), self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def test_orders_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" 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.02 ETH worth of ZRX, and watch for order creation event. current_bid_price: Decimal = self.market.get_price("LINK-ETH", True) bid_price: Decimal = current_bid_price * Decimal("0.8") quantize_bid_price: Decimal = self.market.quantize_order_price("LINK-ETH", bid_price) amount: Decimal = 1 quantized_amount: Decimal = self.market.quantize_order_amount("LINK-ETH", amount) if API_MOCK_ENABLED: resp = self.order_response(FixtureBinance.OPEN_BUY_ORDER, self.get_current_nonce(), "buy", "LINK-ETH") self.web_app.update_response("post", self.base_api_url, "/api/v3/order", resp) order_id = self.market.buy("LINK-ETH", 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.__class__.market: BinanceExchange = BinanceExchange(API_KEY, API_SECRET, ["LINK-ETH", "ZRX-ETH"], True) 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.ev_loop.run_until_complete(self.wait_til_ready()) 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. if API_MOCK_ENABLED: resp = self.fixture(FixtureBinance.CANCEL_ORDER, origClientOrderId=order_id, side="BUY") self.web_app.update_response("delete", self.base_api_url, "/api/v3/order", resp, params={'origClientOrderId': order_id}) self.market.cancel("LINK-ETH", 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("LINK-ETH", order_id) self.run_parallel(self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def setUp(self): self.clock_tick_size = 1 self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size, self.start_timestamp, self.end_timestamp) self.market: BacktestMarket = BacktestMarket() self.book_data: MockOrderBookLoader = MockOrderBookLoader(self.trading_pair, self.base_asset, self.quote_asset) self.mid_price = 100 self.bid_spread = 0.01 self.ask_spread = 0.01 self.order_refresh_time = 30 self.book_data.set_balanced_order_book(mid_price=self.mid_price, min_price=1, max_price=200, price_step_size=1, volume_step_size=10) self.market.add_data(self.book_data) self.market.set_balance("HBOT", 500) self.market.set_balance("ETH", 5000) self.market.set_quantization_param( QuantizationParams( self.trading_pair, 6, 6, 6, 6 ) ) self.market_info = MarketTradingPairTuple(self.market, self.trading_pair, self.base_asset, self.quote_asset) self.clock.add_iterator(self.market) self.order_fill_logger: EventLogger = EventLogger() self.cancel_order_logger: EventLogger = EventLogger() self.market.add_listener(MarketEvent.OrderFilled, self.order_fill_logger) self.market.add_listener(MarketEvent.OrderCancelled, self.cancel_order_logger) self.one_level_strategy = PureMarketMakingStrategy( self.market_info, bid_spread=Decimal("0.01"), ask_spread=Decimal("0.01"), order_amount=Decimal("1"), order_refresh_time=5.0, filled_order_delay=5.0, order_refresh_tolerance_pct=-1, minimum_spread=-1, ) self.multi_levels_strategy = PureMarketMakingStrategy( self.market_info, bid_spread=Decimal("0.01"), ask_spread=Decimal("0.01"), order_amount=Decimal("1"), order_refresh_time=5.0, filled_order_delay=5.0, order_refresh_tolerance_pct=-1, order_levels=3, order_level_spread=Decimal("0.01"), order_level_amount=Decimal("1"), minimum_spread=-1, ) self.order_override_strategy = PureMarketMakingStrategy( self.market_info, bid_spread=Decimal("0.01"), ask_spread=Decimal("0.01"), order_amount=Decimal("1"), order_refresh_time=5.0, filled_order_delay=5.0, order_refresh_tolerance_pct=-1, order_levels=3, order_level_spread=Decimal("0.01"), order_level_amount=Decimal("1"), minimum_spread=-1, order_override={"order_one": ["buy", 0.5, 0.7], "order_two": ["buy", 1.3, 1.1], "order_three": ["sell", 1.1, 2]}, ) self.ext_market: BacktestMarket = BacktestMarket() self.ext_data: MockOrderBookLoader = MockOrderBookLoader(self.trading_pair, self.base_asset, self.quote_asset) self.ext_market_info: MarketTradingPairTuple = MarketTradingPairTuple( self.ext_market, self.trading_pair, self.base_asset, self.quote_asset ) self.ext_data.set_balanced_order_book(mid_price=50, min_price=1, max_price=400, price_step_size=1, volume_step_size=10) self.ext_market.add_data(self.ext_data) self.order_book_asset_del = OrderBookAssetPriceDelegate(self.ext_market, self.trading_pair) trade_fill_sql = SQLConnectionManager( SQLConnectionType.TRADE_FILLS, db_path="" ) self.inventory_cost_price_del = InventoryCostPriceDelegate(trade_fill_sql, self.trading_pair)
def test_orders_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" trading_pair: str = "ETHBTC" 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.0001 ETH, and watch for order creation event. current_bid_price: Decimal = self.market.get_price( trading_pair, True) bid_price: Decimal = current_bid_price * Decimal("0.8") quantize_bid_price: Decimal = self.market.quantize_order_price( trading_pair, bid_price) amount: Decimal = Decimal("0.0001") quantized_amount: Decimal = self.market.quantize_order_amount( trading_pair, amount) order_id = self.market.buy(trading_pair, 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: BitcoinComMarket = BitcoinComMarket( bitcoin_com_api_key=conf.bitcoin_com_api_key, bitcoin_com_secret_key=conf.bitcoin_com_secret_key, trading_pairs=["ETHBTC", "LTCBTC"]) 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(trading_pair, 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(trading_pair, order_id) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
def test_order_saving_and_restoration(self): config_path: str = "test_config" strategy_name: str = "test_strategy" sql: SQLConnectionManager = SQLConnectionManager( SQLConnectionType.TRADE_FILLS, db_path=self.db_path) order_id: Optional[str] = None trading_pair: str = "WETH-USDC" recorder: MarketsRecorder = MarketsRecorder(sql, [self.market], config_path, strategy_name) recorder.start() try: self.assertEqual(0, len(self.market.tracking_states)) self.assertGreater(self.market.get_balance("USDC"), 16000) amount: Decimal = Decimal("40.0") current_bid_price: Decimal = self.market.get_price( trading_pair, True) bid_price: Decimal = Decimal("0.5") * current_bid_price quantize_bid_price: Decimal = self.market.quantize_order_price( trading_pair, bid_price) order_id = self.place_order(True, trading_pair, amount, OrderType.LIMIT, quantize_bid_price, 10001, FixtureDydx.BUY_LIMIT_ORDER, FixtureDydx.WS_AFTER_BUY_1) [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.market_events: self.market.remove_listener(event_tag, self.market_logger) self.market: DydxExchange = DydxExchange( dydx_eth_private_key=PRIVATE_KEY, dydx_node_address=NODE_ADDRESS, poll_interval=10.0, trading_pairs=[trading_pair], trading_required=True) for event_tag in self.market_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.run_parallel(asyncio.sleep(5.0)) self.market.cancel(trading_pair, order_id) if API_MOCK_ENABLED: MockWebSocketServerFactory.send_json_threadsafe( self._ws_user_url, FixtureDydx.WS_AFTER_CANCEL_BUY, delay=0.1) 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(trading_pair, order_id) if API_MOCK_ENABLED: MockWebSocketServerFactory.send_json_threadsafe( self._ws_user_url, FixtureDydx.WS_AFTER_CANCEL_BUY, delay=0.1) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop()