def test_order_fill_record(self): config_path: str = "test_config" strategy_name: str = "test_strategy" symbol: str = "HOT-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: # Try to buy 0.05 ETH worth of HOT from the exchange, and watch for completion event. current_price: Decimal = self.market.get_price(symbol, True) amount: Decimal = Decimal("0.05") / current_price order_id = self.market.buy(symbol, amount) [buy_order_completed_event] = self.run_parallel( self.market_logger.wait_for(BuyOrderCompletedEvent)) # Reset the logs self.market_logger.clear() # Try to sell back the same amount of HOT to the exchange, and watch for completion event. amount = buy_order_completed_event.base_asset_amount order_id = self.market.sell(symbol, 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(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" 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 1 LINK from the exchange, and watch for completion event. bid_price: Decimal = self.market.get_price("LINKETH", True) amount: Decimal = 1 order_id = self.place_order(True, "LINKETH", amount, OrderType.LIMIT, bid_price, 10001, FixtureBinance.ORDER_BUY_LIMIT, FixtureBinance.WS_AFTER_BUY_1, FixtureBinance.WS_AFTER_BUY_2) [buy_order_completed_event] = self.run_parallel(self.market_logger.wait_for(BuyOrderCompletedEvent)) # Reset the logs self.market_logger.clear() # Try to sell back the same amount of LINK to the exchange, and watch for completion event. ask_price: Decimal = self.market.get_price("LINKETH", False) amount = buy_order_completed_event.base_asset_amount order_id = self.place_order(False, "LINKETH", amount, OrderType.LIMIT, ask_price, 10002, FixtureBinance.ORDER_SELL_LIMIT, FixtureBinance.WS_AFTER_SELL_1, FixtureBinance.WS_AFTER_SELL_2) [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.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.market.cancel("LINKETH", 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 = "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: # Try to buy 0.01 ETH from the exchange, and watch for completion event. amount: Decimal = Decimal(0.01) order_id, _ = self.place_order(True, trading_pair, amount, OrderType.MARKET, 0, 10001, FixtureKucoin.ORDER_PLACE, FixtureKucoin.ORDER_GET_MARKET_BUY) [buy_order_completed_event] = self.run_parallel(self.market_logger.wait_for(BuyOrderCompletedEvent)) # Reset the logs self.market_logger.clear() # Try to sell back the same amount of ETH to the exchange, and watch for completion event. amount: Decimal = Decimal(buy_order_completed_event.base_asset_amount) order_id, _ = self.place_order(False, trading_pair, amount, OrderType.MARKET, 0, 10002, FixtureKucoin.ORDER_PLACE, FixtureKucoin.ORDER_GET_MARKET_SELL) [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) self.market_logger.clear()
def test_order_fill_record(self): config_path: str = "test_config" strategy_name: str = "test_strategy" trading_pair: str = "XRP-BTC" 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: current_bid_price: Decimal = self.market.get_price(trading_pair, True) bid_price: Decimal = current_bid_price * Decimal('1.01') quantize_bid_price: Decimal = self.market.quantize_order_price(trading_pair, bid_price) amount: Decimal = Decimal("0.0005") / quantize_bid_price * Decimal('1.1') quantized_amount: Decimal = self.market.quantize_order_amount(trading_pair, amount) order_id = self.market.buy(trading_pair, quantized_amount) [buy_order_completed_event] = self.run_parallel(self.market_logger.wait_for(BuyOrderCompletedEvent)) # Reset the logs self.market_logger.clear() amount = Decimal(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_fill_record(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: amount: Decimal = Decimal("0.06") quantized_amount: Decimal = self.market.quantize_order_amount(trading_pair, amount) order_id, _ = self.place_order(True, trading_pair, quantized_amount, OrderType.MARKET, 0, 10001, FixtureBittrex.ORDER_PLACE_FILLED, FixtureBittrex.WS_ORDER_FILLED) [buy_order_completed_event] = self.run_parallel(self.market_logger.wait_for(BuyOrderCompletedEvent)) # Reset the logs self.market_logger.clear() amount = Decimal(buy_order_completed_event.base_asset_amount) order_id, _ = self.place_order(False, trading_pair, amount, OrderType.MARKET, 0, 10001, FixtureBittrex.ORDER_PLACE_FILLED, FixtureBittrex.WS_ORDER_FILLED) [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 _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()
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: KrakenMarket = KrakenMarket(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" 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)
def test_z_orders_saving_and_restoration(self): self.market.reset_state() config_path: str = "test_config" strategy_name: str = "test_strategy" symbol: str = self.base_token_symbol + "-" + self.quote_token_symbol 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: 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.05 / bid_price quantized_amount: Decimal = self.market.quantize_order_amount(symbol, amount) expires = int(time.time() + 60 * 5) order_id = self.market.buy(symbol, float(quantized_amount), OrderType.LIMIT, float(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, symbols=[conf.test_bamboo_relay_base_token_symbol + "-" + conf.test_bamboo_relay_quote_token_symbol], use_coordinator=True, pre_emptive_soft_cancels=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["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(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["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(symbol, 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 = "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)
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()
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: 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.ORDER_GET_BUY_UNMATCHED) [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.ORDER_CANCEL.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.ORDER_GET_CANCELLED.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" 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" 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("LINKETH", True) bid_price: Decimal = current_bid_price * Decimal("0.8") quantize_bid_price: Decimal = self.market.quantize_order_price( "LINKETH", bid_price) amount: Decimal = 1 quantized_amount: Decimal = self.market.quantize_order_amount( "LINKETH", amount) if API_MOCK_ENABLED: resp = self.order_response(FixtureBinance.ORDER_BUY_NOT_FILLED, 1000001, "buy", "LINKETH") self.web_app.update_response("post", self.base_api_url, "/api/v3/order", resp) order_id = self.market.buy("LINKETH", 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=API_KEY, binance_api_secret=API_SECRET, order_book_tracker_data_source_type= OrderBookTrackerDataSourceType.EXCHANGE_API, user_stream_tracker_data_source_type= UserStreamTrackerDataSourceType.EXCHANGE_API, trading_pairs=["LINKETH", "ZRXETH"]) 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: 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("LINKETH", 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("LINKETH", order_id) self.run_parallel( self.market_logger.wait_for(OrderCancelledEvent)) recorder.stop() os.unlink(self.db_path)
class HummingbotApplication(*commands): KILL_TIMEOUT = 10.0 APP_WARNING_EXPIRY_DURATION = 3600.0 APP_WARNING_STATUS_LIMIT = 6 _main_app: Optional["HummingbotApplication"] = None @classmethod def logger(cls) -> HummingbotLogger: global s_logger if s_logger is None: s_logger = logging.getLogger(__name__) return s_logger @classmethod def main_application(cls) -> "HummingbotApplication": if cls._main_app is None: cls._main_app = HummingbotApplication() return cls._main_app def __init__(self): self.ev_loop: asyncio.BaseEventLoop = asyncio.get_event_loop() self.parser: ThrowingArgumentParser = load_parser(self) self.app = HummingbotCLI(input_handler=self._handle_command, bindings=load_key_bindings(self), completer=load_completer(self)) self.markets: Dict[str, MarketBase] = {} self.wallet: Optional[Web3Wallet] = None # strategy file name and name get assigned value after import or create command self.strategy_file_name: str = None self.strategy_name: str = None self.strategy_task: Optional[asyncio.Task] = None self.strategy: Optional[StrategyBase] = None self.market_pair: Optional[CrossExchangeMarketPair] = None self.market_trading_pair_tuples: List[MarketTradingPairTuple] = [] self.clock: Optional[Clock] = None self.init_time: int = int(time.time() * 1e3) self.start_time: Optional[int] = None self.assets: Optional[Set[str]] = set() self.starting_balances = {} self.placeholder_mode = False self.log_queue_listener: Optional[ logging.handlers.QueueListener] = None self.data_feed: Optional[DataFeedBase] = None self.notifiers: List[NotifierBase] = [] self.kill_switch: Optional[KillSwitch] = None self._app_warnings: Deque[ApplicationWarning] = deque() self._trading_required: bool = True self.trade_fill_db: SQLConnectionManager = SQLConnectionManager.get_trade_fills_instance( ) self.markets_recorder: Optional[MarketsRecorder] = None self._script_iterator = None @property def strategy_config_map(self): if self.strategy_name is not None: return get_strategy_config_map(self.strategy_name) return None def _notify(self, msg: str): self.app.log(msg) for notifier in self.notifiers: notifier.add_msg_to_queue(msg) def _handle_command(self, raw_command: str): # unset to_stop_config flag it triggered before loading any command if self.app.to_stop_config: self.app.to_stop_config = False raw_command = raw_command.lower().strip() try: if self.placeholder_mode: pass else: args = self.parser.parse_args(args=raw_command.split()) kwargs = vars(args) if not hasattr(args, "func"): return f = args.func del kwargs["func"] f(**kwargs) except InvalidCommandError as e: self._notify("Invalid command: %s" % (str(e), )) except ArgumentParserError as e: if not self.be_silly(raw_command): self._notify(str(e)) except NotImplementedError: self._notify( "Command not yet implemented. This feature is currently under development." ) except Exception as e: self.logger().error(e, exc_info=True) async def _cancel_outstanding_orders(self) -> bool: success = True try: on_chain_cancel_on_exit = global_config_map.get( "on_chain_cancel_on_exit").value bamboo_relay_use_coordinator = global_config_map.get( "bamboo_relay_use_coordinator").value kill_timeout: float = self.KILL_TIMEOUT self._notify("Cancelling outstanding orders...") for market_name, market in self.markets.items(): # By default, the bot does not cancel orders on exit on Radar Relay or Bamboo Relay, # since all open orders will expire in a short window if not on_chain_cancel_on_exit and ( market_name == "radar_relay" or (market_name == "bamboo_relay" and not bamboo_relay_use_coordinator)): continue cancellation_results = await market.cancel_all(kill_timeout) uncancelled = list( filter(lambda cr: cr.success is False, cancellation_results)) if len(uncancelled) > 0: success = False uncancelled_order_ids = list( map(lambda cr: cr.order_id, uncancelled)) self._notify( "\nFailed to cancel the following orders on %s:\n%s" % (market_name, '\n'.join(uncancelled_order_ids))) except Exception: self.logger().error("Error canceling outstanding orders.", exc_info=True) success = False if success: self._notify("All outstanding orders cancelled.") return success async def run(self): await self.app.run() def add_application_warning(self, app_warning: ApplicationWarning): self._expire_old_application_warnings() self._app_warnings.append(app_warning) def clear_application_warning(self): self._app_warnings.clear() @staticmethod def _initialize_market_assets( market_name: str, trading_pairs: List[str]) -> List[Tuple[str, str]]: market_class: MarketBase = MARKET_CLASSES.get(market_name, MarketBase) market_trading_pairs: List[Tuple[str, str]] = [ market_class.split_trading_pair(trading_pair) for trading_pair in trading_pairs ] return market_trading_pairs @staticmethod def _convert_to_exchange_trading_pair( market_name: str, hb_trading_pair: List[str]) -> List[str]: market_class: MarketBase = MARKET_CLASSES.get(market_name, MarketBase) return [ market_class.convert_to_exchange_trading_pair(trading_pair) for trading_pair in hb_trading_pair ] def _initialize_wallet(self, token_trading_pairs: List[str]): if not using_wallet(): return ethereum_wallet = global_config_map.get("ethereum_wallet").value private_key = Security._private_keys[ethereum_wallet] ethereum_rpc_url = global_config_map.get("ethereum_rpc_url").value erc20_token_addresses = get_erc20_token_addresses(token_trading_pairs) chain_name: str = global_config_map.get("ethereum_chain_name").value self.wallet: Web3Wallet = Web3Wallet( private_key=private_key, backend_urls=[ethereum_rpc_url], erc20_token_addresses=erc20_token_addresses, chain=getattr(EthereumChain, chain_name), ) 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() def _initialize_notifiers(self): if global_config_map.get("telegram_enabled").value: # TODO: refactor to use single instance if not any( [isinstance(n, TelegramNotifier) for n in self.notifiers]): self.notifiers.append( TelegramNotifier( token=global_config_map["telegram_token"].value, chat_id=global_config_map["telegram_chat_id"].value, hb=self, )) for notifier in self.notifiers: notifier.start()
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_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, trading_pairs=["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)
class HummingbotApplication(*commands): KILL_TIMEOUT = 10.0 IDEX_KILL_TIMEOUT = 30.0 APP_WARNING_EXPIRY_DURATION = 3600.0 APP_WARNING_STATUS_LIMIT = 6 _main_app: Optional["HummingbotApplication"] = None @classmethod def logger(cls) -> HummingbotLogger: global s_logger if s_logger is None: s_logger = logging.getLogger(__name__) return s_logger @classmethod def main_application(cls) -> "HummingbotApplication": if cls._main_app is None: cls._main_app = HummingbotApplication() return cls._main_app def __init__(self): self.ev_loop: asyncio.BaseEventLoop = asyncio.get_event_loop() self.parser: ThrowingArgumentParser = load_parser(self) self.app = HummingbotCLI( input_handler=self._handle_command, bindings=load_key_bindings(self), completer=load_completer(self)) self.acct: Optional[LocalAccount] = None self.markets: Dict[str, MarketBase] = {} self.wallet: Optional[Web3Wallet] = None self.strategy_task: Optional[asyncio.Task] = None self.strategy: Optional[StrategyBase] = None self.market_pair: Optional[CrossExchangeMarketPair] = None self.market_trading_pair_tuples: List[MarketTradingPairTuple] = [] self.clock: Optional[Clock] = None self.init_time: int = int(time.time() * 1e3) self.start_time: Optional[int] = None self.assets: Optional[Set[str]] = set() self.starting_balances = {} self.placeholder_mode = False self.log_queue_listener: Optional[logging.handlers.QueueListener] = None self.reporting_module: Optional[ReportAggregator] = None self.data_feed: Optional[DataFeedBase] = None self.notifiers: List[NotifierBase] = [] self.kill_switch: Optional[KillSwitch] = None self.liquidity_bounty: Optional[LiquidityBounty] = None self._initialize_liquidity_bounty() self._app_warnings: Deque[ApplicationWarning] = deque() self._trading_required: bool = True self.trade_fill_db: SQLConnectionManager = SQLConnectionManager.get_trade_fills_instance() self.markets_recorder: Optional[MarketsRecorder] = None def init_reporting_module(self): if not self.reporting_module: self.reporting_module = ReportAggregator( self, report_aggregation_interval=global_config_map["reporting_aggregation_interval"].value, log_report_interval=global_config_map["reporting_log_interval"].value) self.reporting_module.start() def _notify(self, msg: str): self.app.log(msg) for notifier in self.notifiers: notifier.add_msg_to_queue(msg) def _handle_command(self, raw_command: str): raw_command = raw_command.lower().strip() try: if self.placeholder_mode: pass else: logging.getLogger("hummingbot.command_history").info(raw_command) args = self.parser.parse_args(args=raw_command.split()) kwargs = vars(args) if not hasattr(args, "func"): return f = args.func del kwargs['func'] f(**kwargs) except InvalidCommandError as e: self._notify("Invalid command: %s" % (str(e),)) except ArgumentParserError as e: self._notify(str(e)) except NotImplementedError: self._notify("Command not yet implemented. This feature is currently under development.") except Exception as e: self.logger().error(e, exc_info=True) async def _cancel_outstanding_orders(self) -> bool: success = True try: on_chain_cancel_on_exit = global_config_map.get("on_chain_cancel_on_exit").value bamboo_relay_use_coordinator = global_config_map.get("bamboo_relay_use_coordinator").value kill_timeout: float = self.KILL_TIMEOUT self._notify("Cancelling outstanding orders...") for market_name, market in self.markets.items(): if market_name == "idex": self._notify(f"IDEX cancellations may take up to {int(self.IDEX_KILL_TIMEOUT)} seconds...") kill_timeout = self.IDEX_KILL_TIMEOUT # By default, the bot does not cancel orders on exit on Radar Relay or Bamboo Relay, # since all open orders will expire in a short window if not on_chain_cancel_on_exit and (market_name == "radar_relay" or (market_name == "bamboo_relay" and not bamboo_relay_use_coordinator)): continue cancellation_results = await market.cancel_all(kill_timeout) uncancelled = list(filter(lambda cr: cr.success is False, cancellation_results)) if len(uncancelled) > 0: success = False uncancelled_order_ids = list(map(lambda cr: cr.order_id, uncancelled)) self._notify("\nFailed to cancel the following orders on %s:\n%s" % ( market_name, '\n'.join(uncancelled_order_ids) )) except Exception: self.logger().error(f"Error canceling outstanding orders.", exc_info=True) success = False if success: self._notify("All outstanding orders cancelled.") return success async def run(self): await self.app.run() def add_application_warning(self, app_warning: ApplicationWarning): self._expire_old_application_warnings() self._app_warnings.append(app_warning) def clear_application_warning(self): self._app_warnings.clear() @staticmethod def _initialize_market_assets(market_name: str, symbols: List[str]) -> List[Tuple[str, str]]: market: MarketBase = MARKET_CLASSES.get(market_name, MarketBase) market_symbols: List[Tuple[str, str]] = [market.split_symbol(symbol) for symbol in symbols] return market_symbols def _initialize_wallet(self, token_symbols: List[str]): ethereum_rpc_url = global_config_map.get("ethereum_rpc_url").value erc20_token_addresses = get_erc20_token_addresses(token_symbols) if self.acct is not None: self.wallet: Web3Wallet = Web3Wallet(private_key=self.acct.privateKey, backend_urls=[ethereum_rpc_url], erc20_token_addresses=erc20_token_addresses, chain=EthereumChain.MAIN_NET) 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() def _initialize_notifiers(self): if global_config_map.get("telegram_enabled").value: # TODO: refactor to use single instance if not any([isinstance(n, TelegramNotifier) for n in self.notifiers]): self.notifiers.append(TelegramNotifier(token=global_config_map["telegram_token"].value, chat_id=global_config_map["telegram_chat_id"].value, hb=self)) for notifier in self.notifiers: notifier.start() def _initialize_liquidity_bounty(self): if liquidity_bounty_config_map.get("liquidity_bounty_enabled").value is not None and \ liquidity_bounty_config_map.get("liquidity_bounty_client_id").value is not None: self.liquidity_bounty = LiquidityBounty.get_instance() self.liquidity_bounty.start()
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 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: try: market = IDEXMarket( 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: market = BambooRelayMarket(wallet=self.wallet, ethereum_rpc_url=ethereum_rpc_url, symbols=symbols) 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) 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()