async def docker_ipc_with_generator(method_name: str, *args, **kwargs) -> AsyncIterable[str]: from hummingbot.client.hummingbot_application import HummingbotApplication global _hummingbot_pipe if _hummingbot_pipe is None: raise RuntimeError( "Not in the main process, or hummingbot wasn't started via `fork_and_start()`." ) try: _hummingbot_pipe.send((method_name, args, kwargs)) while True: data = await _hummingbot_pipe.coro_recv() if data is None: break if isinstance(data, Exception): HummingbotApplication.main_application().notify( "\nError: Unable to communicate with docker socket. " "\nEnsure dockerd is running and /var/run/docker.sock exists, then restart Hummingbot." ) raise data yield data except Exception as e: # unable to communicate with docker socket HummingbotApplication.main_application().notify( "\nError: Unable to communicate with docker socket. " "\nEnsure dockerd is running and /var/run/docker.sock exists, then restart Hummingbot." ) raise e
def setUp(self, _: MagicMock) -> None: super().setUp() self.app = HummingbotApplication() self.ev_loop = asyncio.get_event_loop() self.cli_mock_assistant = CLIMockingAssistant(self.app.app) self.cli_mock_assistant.start() self.global_config_backup = deepcopy(global_config_map)
def notify_hb_app(self, msg: str): """ Send a message to the hummingbot application """ if self._hb_app_notification: from hummingbot.client.hummingbot_application import HummingbotApplication HummingbotApplication.main_application()._notify(msg)
def setUp(self, _: MagicMock) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.async_run_with_timeout(read_system_configs_from_yml()) self.app = HummingbotApplication() self.global_config_backup = deepcopy(global_config_map)
def setUp(self, _: MagicMock) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.async_run_with_timeout(read_system_configs_from_yml()) self.app = HummingbotApplication() self.cli_mock_assistant = CLIMockingAssistant(self.app.app) self.cli_mock_assistant.start()
def setUp(self, _: MagicMock) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.async_run_with_timeout(read_system_configs_from_yml()) self.client_config_map = ClientConfigAdapter(ClientConfigMap()) self.app = HummingbotApplication( client_config_map=self.client_config_map)
async def start_existing_gateway_container( client_config_map: "ClientConfigAdapter"): container_info: Optional[Dict[ str, Any]] = await detect_existing_gateway_container(client_config_map) if container_info is not None and container_info["State"] != "running": from hummingbot.client.hummingbot_application import HummingbotApplication HummingbotApplication.main_application().logger().info( "Starting existing Gateway container...") await docker_ipc("start", get_gateway_container_name(client_config_map))
class PreviousCommandUnitTest(unittest.TestCase): def setUp(self) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.async_run_with_timeout(read_system_configs_from_yml()) self.client_config = ClientConfigMap() self.config_adapter = ClientConfigAdapter(self.client_config) self.app = HummingbotApplication(self.config_adapter) self.cli_mock_assistant = CLIMockingAssistant(self.app.app) self.cli_mock_assistant.start() def tearDown(self) -> None: self.cli_mock_assistant.stop() super().tearDown() def async_run_with_timeout(self, coroutine: Awaitable, timeout: float = 1): ret = self.ev_loop.run_until_complete( asyncio.wait_for(coroutine, timeout)) return ret def mock_user_response(self, config): config.value = "yes" def test_no_previous_strategy_found(self): self.config_adapter.previous_strategy = None self.app.previous_strategy(option="") self.assertTrue( self.cli_mock_assistant.check_log_called_with( "No previous strategy found.")) @patch( "hummingbot.client.command.import_command.ImportCommand.import_command" ) def test_strategy_found_and_user_declines(self, import_command: MagicMock): strategy_name = "conf_1.yml" self.cli_mock_assistant.queue_prompt_reply("No") self.async_run_with_timeout( self.app.prompt_for_previous_strategy(strategy_name)) import_command.assert_not_called() @patch( "hummingbot.client.command.import_command.ImportCommand.import_command" ) def test_strategy_found_and_user_accepts(self, import_command: MagicMock): strategy_name = "conf_1.yml" self.config_adapter.previous_strategy = strategy_name self.cli_mock_assistant.queue_prompt_reply("Yes") self.async_run_with_timeout( self.app.prompt_for_previous_strategy(strategy_name)) import_command.assert_called() self.assertTrue(import_command.call_args[0][1] == strategy_name)
def setUp(self) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.async_run_with_timeout(read_system_configs_from_yml()) self.client_config = ClientConfigMap() self.config_adapter = ClientConfigAdapter(self.client_config) self.app = HummingbotApplication(self.config_adapter) self.cli_mock_assistant = CLIMockingAssistant(self.app.app) self.cli_mock_assistant.start()
def setUp(self, _: MagicMock) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.async_run_with_timeout(read_system_configs_from_yml()) self.app = HummingbotApplication() self.cli_mock_assistant = CLIMockingAssistant(self.app.app) self.cli_mock_assistant.start() self.global_config_backup = deepcopy(global_config_map) self.mock_strategy_name = "test-strategy"
async def main(): await create_yml_files() # This init_logging() call is important, to skip over the missing config warnings. init_logging("hummingbot_logs.yml") read_configs_from_yml() if __name__ == '__main__': hb = HummingbotApplication.main_application() with patch_stdout(log_field=hb.app.log_field): dev_mode = check_dev_mode() if dev_mode: hb.app.log( "Running from dev branches. Full remote logging will be enabled." ) init_logging( "hummingbot_logs.yml", override_log_level=global_config_map.get("log_level").value, dev_mode=dev_mode) tasks: List[Coroutine] = [hb.run()] if global_config_map.get("debug_console").value: management_port: int = detect_available_port(8211) tasks.append( start_management_console(locals(), host="localhost", port=management_port)) await asyncio.gather(*tasks)
async def get_connector_price(self, connector_name: str, chain: str, network: str, trading_pair: str, is_buy: bool, amount: Decimal) -> Optional[Decimal]: key: GatewayPriceShimKey = GatewayPriceShimKey( connector_name=connector_name, chain=chain, network=network, trading_pair=trading_pair) if key not in self._shim_entries: return None shim_entry: GatewayPriceShimEntry = self._shim_entries[key] exchange_market: Optional[ ExchangeBase] = HummingbotApplication.main_application( ).markets.get(shim_entry.from_exchange) if exchange_market is None: self.logger().warning( f"Gateway price shim failure: " f"reference exchange market '{shim_entry.from_exchange}' not found. " f"Going to use on-chain prices instead.") return None exchange_price: Decimal = await exchange_market.get_quote_price( shim_entry.from_trading_pair, is_buy, amount) if key in self._delta_entries: delta_entry: GatewayPriceDeltaEntry = self._delta_entries[key] now: float = time.time() if now <= delta_entry.end_timestamp: exchange_price += delta_entry.delta else: del self._delta_entries[key] return exchange_price
async def main_async(client_config_map: ClientConfigAdapter): await create_yml_files_legacy() # This init_logging() call is important, to skip over the missing config warnings. init_logging("hummingbot_logs.yml", client_config_map) AllConnectorSettings.initialize_paper_trade_settings( client_config_map.paper_trade.paper_trade_exchanges) hb = HummingbotApplication.main_application(client_config_map) # The listener needs to have a named variable for keeping reference, since the event listener system # uses weak references to remove unneeded listeners. start_listener: UIStartListener = UIStartListener(hb) hb.app.add_listener(HummingbotUIEvent.Start, start_listener) tasks: List[Coroutine] = [ hb.run(), start_existing_gateway_container(client_config_map) ] if client_config_map.debug_console: if not hasattr(__builtins__, "help"): import _sitebuiltins __builtins__.help = _sitebuiltins._Helper() from hummingbot.core.management.console import start_management_console management_port: int = detect_available_port(8211) tasks.append( start_management_console(locals(), host="localhost", port=management_port)) await safe_gather(*tasks)
async def quick_start(args): config_file_name = args.config_file_name wallet = args.wallet password = args.config_password if args.auto_set_permissions is not None: autofix_permissions(args.auto_set_permissions) if password is not None and not Security.login(password): logging.getLogger().error("Invalid password.") return await Security.wait_til_decryption_done() await create_yml_files() init_logging("hummingbot_logs.yml") read_system_configs_from_yml() hb = HummingbotApplication.main_application() # Todo: validate strategy and config_file_name before assinging if config_file_name is not None: hb.strategy_file_name = config_file_name hb.strategy_name = update_strategy_config_map_from_file( os.path.join(CONF_FILE_PATH, config_file_name)) # To ensure quickstart runs with the default value of False for kill_switch_enabled if not present if not global_config_map.get("kill_switch_enabled"): global_config_map.get("kill_switch_enabled").value = False if wallet and password: global_config_map.get("ethereum_wallet").value = wallet if hb.strategy_name and hb.strategy_file_name: if not all_configs_complete(hb.strategy_name): hb.status() with patch_stdout(log_field=hb.app.log_field): dev_mode = check_dev_mode() if dev_mode: hb.app.log( "Running from dev branches. Full remote logging will be enabled." ) log_level = global_config_map.get("log_level").value init_logging("hummingbot_logs.yml", override_log_level=log_level, dev_mode=dev_mode) if hb.strategy_file_name is not None and hb.strategy_name is not None: await write_config_to_yml(hb.strategy_name, hb.strategy_file_name) hb.start(log_level) tasks: List[Coroutine] = [hb.run()] if global_config_map.get("debug_console").value: management_port: int = detect_available_port(8211) tasks.append( start_management_console(locals(), host="localhost", port=management_port)) await safe_gather(*tasks)
async def main(): await create_yml_files() # This init_logging() call is important, to skip over the missing config warnings. init_logging("hummingbot_logs.yml") read_system_configs_from_yml() hb = HummingbotApplication.main_application() with patch_stdout(log_field=hb.app.log_field): dev_mode = check_dev_mode() if dev_mode: hb.app.log("Running from dev branches. Full remote logging will be enabled.") init_logging("hummingbot_logs.yml", override_log_level=global_config_map.get("log_level").value, dev_mode=dev_mode) tasks: List[Coroutine] = [hb.run()] if global_config_map.get("debug_console").value: if not hasattr(__builtins__, "help"): import _sitebuiltins __builtins__.help = _sitebuiltins._Helper() from hummingbot.core.management.console import start_management_console management_port: int = detect_available_port(8211) tasks.append(start_management_console(locals(), host="localhost", port=management_port)) await safe_gather(*tasks)
def get_gateway_status(): from hummingbot.client.hummingbot_application import HummingbotApplication hb = HummingbotApplication.main_application() gateway_status = "RUNNING" if hb._gateway_monitor.current_status is GatewayStatus.ONLINE else "STOPPED" gateway_conn_status = hb._gateway_monitor.current_connector_conn_status.name style = "class:log_field" return [(style, f"Gateway: {gateway_status}, {gateway_conn_status}")]
async def main(): chdir_to_data_directory() await create_yml_files() # This init_logging() call is important, to skip over the missing config warnings. init_logging("hummingbot_logs.yml") hb = HummingbotApplication.main_application() setHummingInstance(hb) read_configs_from_yml() ExchangeRateConversion.get_instance().start() with patch_stdout(log_field=hb.app.log_field): dev_mode = check_dev_mode() if dev_mode: hb.app.log( "Running from dev branches. Full remote logging will be enabled." ) init_logging( "hummingbot_logs.yml", override_log_level=global_config_map.get("log_level").value, dev_mode=dev_mode) tasks: List[Coroutine] = [hb.run(), sio.connect('ws://localhost:5000')] await safe_gather(*tasks)
def notify(self, msg: str): from . import INFO self.log(INFO, msg) if not HummingbotLogger.is_testing_mode(): from hummingbot.client.hummingbot_application import HummingbotApplication hummingbot_app: HummingbotApplication = HummingbotApplication.main_application() hummingbot_app._notify(f"({pd.Timestamp.fromtimestamp(int(time.time()))}) {msg}")
def test_notify_hb_app_with_timestamp(self, cli_class_mock, main_application_function_mock): messages = [] cli_logs = [] cli_instance = cli_class_mock.return_value cli_instance.log.side_effect = lambda message: cli_logs.append(message) notifier_mock = unittest.mock.MagicMock() notifier_mock.add_msg_to_queue.side_effect = lambda message: messages.append( message) hummingbot_application = HummingbotApplication() hummingbot_application.notifiers.append(notifier_mock) main_application_function_mock.return_value = hummingbot_application time_of_tick = datetime(year=2021, month=6, day=17, hour=0, minute=0, second=0, microsecond=0) self.strategy.tick(time_of_tick.timestamp()) self.strategy.notify_hb_app_with_timestamp("Test message") self.assertIn("(2021-06-17 00:00:00) Test message", cli_logs) self.assertIn("(2021-06-17 00:00:00) Test message", messages)
async def set_up_class(cls): add_files_extension(settings.CONF_FILE_PATH, [".yml", ".json"], ".temp") asyncio.ensure_future(hb_main()) cls.hb = HummingbotApplication.main_application() await wait_til(lambda: 'Enter "config" to create a bot' in cls.hb.app. output_field.document.text)
def non_trading_connector_instance_with_default_configuration( self, trading_pairs: Optional[List[str]] = None) -> 'ConnectorBase': from hummingbot.client.config.config_helpers import ClientConfigAdapter from hummingbot.client.hummingbot_application import HummingbotApplication trading_pairs = trading_pairs or [] connector_class = getattr(importlib.import_module(self.module_path()), self.class_name()) kwargs = {} if isinstance(self.config_keys, Dict): kwargs = { key: (config.value or "") for key, config in self.config_keys.items() } # legacy elif self.config_keys is not None: kwargs = { traverse_item.attr: traverse_item.value.get_secret_value() if isinstance(traverse_item.value, SecretStr) else traverse_item.value or "" for traverse_item in ClientConfigAdapter( self.config_keys).traverse() if traverse_item.attr != "connector" } kwargs = self.conn_init_parameters(kwargs) kwargs = self.add_domain_parameter(kwargs) kwargs.update(trading_pairs=trading_pairs, trading_required=False) kwargs["client_config_map"] = HummingbotApplication.main_application( ).client_config_map connector = connector_class(**kwargs) return connector
class TickerCommandTest(unittest.TestCase): @patch("hummingbot.core.utils.trading_pair_fetcher.TradingPairFetcher") def setUp(self, _: MagicMock) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.async_run_with_timeout(read_system_configs_from_yml()) self.app = HummingbotApplication() self.global_config_backup = deepcopy(global_config_map) def tearDown(self) -> None: self.reset_global_config() super().tearDown() def async_run_with_timeout(self, coroutine: Awaitable, timeout: float = 1): ret = self.ev_loop.run_until_complete( asyncio.wait_for(coroutine, timeout)) return ret def reset_global_config(self): for key, value in self.global_config_backup.items(): global_config_map[key] = value @patch( "hummingbot.client.hummingbot_application.HummingbotApplication.notify" ) def test_show_ticker(self, notify_mock): global_config_map["tables_format"].value = "psql" captures = [] notify_mock.side_effect = lambda s: captures.append(s) exchange_name = "paper" exchange = MockPaperExchange() self.app.markets[exchange_name] = exchange trading_pair = "BTC-USDT" exchange.set_balanced_order_book( trading_pair, mid_price=10, min_price=8.5, max_price=11.5, price_step_size=1, volume_step_size=1, ) self.async_run_with_timeout( self.app.show_ticker(exchange=exchange_name, live=False)) self.assertEqual(1, len(captures)) df_str_expected = ( " Market: MockPaperExchange" "\n+------------+------------+-------------+--------------+" "\n| Best Bid | Best Ask | Mid Price | Last Trade |" "\n|------------+------------+-------------+--------------|" "\n| 9.5 | 10.5 | 10 | nan |" "\n+------------+------------+-------------+--------------+") self.assertEqual(df_str_expected, captures[0])
async def start_trade_monitor(trade_monitor): from hummingbot.client.hummingbot_application import HummingbotApplication hb = HummingbotApplication.main_application() trade_monitor.log("Trades: 0, Total P&L: 0.00, Return %: 0.00%") total_trades = 0 return_pcts = [] pnls = [] quote_asset = "" while True: if hb.strategy_task is not None and not hb.strategy_task.done(): if all(market.ready for market in hb.markets.values()): trades: List[TradeFill] = hb._get_trades_from_session(int(hb.init_time * 1e3), config_file_path=hb.strategy_file_name) if len(trades) > total_trades: total_trades = len(trades) market_info: Set[Tuple[str, str]] = set((t.market, t.symbol) for t in trades) for market, symbol in market_info: quote_asset = symbol.split("-")[1] # Note that the qiote asset of the last pair is assumed to be the quote asset of P&L for simplicity cur_trades = [t for t in trades if t.market == market and t.symbol == symbol] cur_balances = await hb.get_current_balances(market) cur_price = await get_last_price(market.replace("_PaperTrade", ""), symbol) perf = calculate_performance_metrics(symbol, cur_trades, cur_balances, cur_price) return_pcts.append(perf.return_pct) pnls.append(perf.total_pnl) avg_return = sum(return_pcts) / len(return_pcts) if len(return_pcts) > 0 else s_decimal_0 total_pnls = sum(pnls) # Note that this sum doesn't handles cases with different multiple pairs for simplisity trade_monitor.log(f"Trades: {total_trades}, Total P&L: {smart_round(total_pnls)} {quote_asset}, Return %: {avg_return:.2%}") return_pcts.clear() pnls.clear() await asyncio.sleep(2) # sleeping for longer to manage resources
async def quick_start(): try: args = CmdlineParser().parse_args() strategy = args.strategy config_file_name = args.config_file_name wallet = args.wallet password = args.config_password await create_yml_files() init_logging("hummingbot_logs.yml") read_configs_from_yml() ExchangeRateConversion.get_instance().start() await ExchangeRateConversion.get_instance().wait_till_ready() hb = HummingbotApplication.main_application() in_memory_config_map.get("password").value = password in_memory_config_map.get("strategy").value = strategy in_memory_config_map.get("strategy").validate(strategy) in_memory_config_map.get("strategy_file_path").value = config_file_name in_memory_config_map.get("strategy_file_path").validate(config_file_name) # To ensure quickstart runs with the default value of False for kill_switch_enabled if not present if not global_config_map.get("kill_switch_enabled"): global_config_map.get("kill_switch_enabled").value = False if wallet and password: global_config_map.get("wallet").value = wallet hb.acct = unlock_wallet(public_key=wallet, password=password) if not hb.config_complete: config_map = load_required_configs() empty_configs = [key for key, config in config_map.items() if config.value is None and config.required] empty_config_description: str = "\n- ".join([""] + empty_configs) raise ValueError(f"Missing empty configs: {empty_config_description}\n") with patch_stdout(log_field=hb.app.log_field): dev_mode = check_dev_mode() if dev_mode: hb.app.log("Running from dev branches. Full remote logging will be enabled.") log_level = global_config_map.get("log_level").value init_logging("hummingbot_logs.yml", override_log_level=log_level, dev_mode=dev_mode, strategy_file_path=config_file_name) await write_config_to_yml() hb.start(log_level) tasks: List[Coroutine] = [hb.run()] if global_config_map.get("debug_console").value: management_port: int = detect_available_port(8211) tasks.append(start_management_console(locals(), host="localhost", port=management_port)) await safe_gather(*tasks) except Exception as e: # In case of quick start failure, start the bot normally to allow further configuration logging.getLogger().warning(f"Bot config incomplete: {str(e)}. Starting normally...") await normal_start()
def test_get_active_strategy(self): hb = HummingbotApplication.main_application() hb.strategy_name = "SomeStrategy" res = get_active_strategy() style, text = res[0] self.assertEqual("class:log-field", style) self.assertEqual(f"Strategy: {hb.strategy_name}", text)
def test_get_strategy_file(self): hb = HummingbotApplication.main_application() hb._strategy_file_name = "some_strategy.yml" res = get_strategy_file() style, text = res[0] self.assertEqual("class:log-field", style) self.assertEqual(f"Strategy File: {hb._strategy_file_name}", text)
async def quick_start(): try: args = CmdlineParser().parse_args() strategy = args.strategy config_file_name = args.config_file_name wallet = args.wallet wallet_password = args.wallet_password await create_yml_files() init_logging("hummingbot_logs.yml") read_configs_from_yml() hb = HummingbotApplication.main_application() in_memory_config_map.get("strategy").value = strategy in_memory_config_map.get("strategy").validate(strategy) in_memory_config_map.get("strategy_file_path").value = config_file_name in_memory_config_map.get("strategy_file_path").validate( config_file_name) if wallet and wallet_password: global_config_map.get("wallet").value = wallet hb.acct = unlock_wallet(public_key=wallet, password=wallet_password) if not hb.config_complete: empty_configs = hb._get_empty_configs() empty_config_description: str = "\n- ".join([""] + empty_configs) raise ValueError( f"Missing empty configs: {empty_config_description}\n") with patch_stdout(log_field=hb.app.log_field): dev_mode = check_dev_mode() if dev_mode: hb.app.log( "Running from dev branches. Full remote logging will be enabled." ) log_level = global_config_map.get("log_level").value init_logging("hummingbot_logs.yml", override_log_level=log_level, dev_mode=dev_mode) hb.start(log_level) tasks: List[Coroutine] = [hb.run()] if global_config_map.get("debug_console").value: management_port: int = detect_available_port(8211) tasks.append( start_management_console(locals(), host="localhost", port=management_port)) await asyncio.gather(*tasks) except Exception as e: # In case of quick start failure, start the bot normally to allow further configuration logging.getLogger().warning( f"Bot config incomplete: {str(e)}. Starting normally...") await normal_start()
class OrderBookCommandTest(unittest.TestCase): @patch("hummingbot.core.utils.trading_pair_fetcher.TradingPairFetcher") def setUp(self, _: MagicMock) -> None: super().setUp() self.ev_loop = asyncio.get_event_loop() self.async_run_with_timeout(read_system_configs_from_yml()) self.client_config_map = ClientConfigAdapter(ClientConfigMap()) self.app = HummingbotApplication( client_config_map=self.client_config_map) def async_run_with_timeout(self, coroutine: Awaitable, timeout: float = 1): ret = self.ev_loop.run_until_complete( asyncio.wait_for(coroutine, timeout)) return ret @patch( "hummingbot.client.hummingbot_application.HummingbotApplication.notify" ) def test_show_order_book(self, notify_mock): self.client_config_map.db_mode = DBSqliteMode() captures = [] notify_mock.side_effect = lambda s: captures.append(s) exchange_name = "paper" exchange = MockPaperExchange( client_config_map=ClientConfigAdapter(ClientConfigMap())) self.app.markets[exchange_name] = exchange trading_pair = "BTC-USDT" exchange.set_balanced_order_book( trading_pair, mid_price=10, min_price=8.5, max_price=11.5, price_step_size=1, volume_step_size=1, ) self.async_run_with_timeout( self.app.show_order_book(exchange=exchange_name, live=False)) self.assertEqual(1, len(captures)) df_str_expected = ( " market: mock_paper_exchange BTC-USDT" "\n +-------------+--------------+-------------+--------------+" "\n | bid_price | bid_volume | ask_price | ask_volume |" "\n |-------------+--------------+-------------+--------------|" "\n | 9.5 | 1 | 10.5 | 1 |" "\n | 8.5 | 2 | 11.5 | 2 |" "\n +-------------+--------------+-------------+--------------+" ) self.assertEqual(df_str_expected, captures[0])
def __init__(self, client_config_map: Optional["ClientConfigAdapter"] = None): if client_config_map is None: from hummingbot.client.hummingbot_application import HummingbotApplication client_config_map = HummingbotApplication.main_application().client_config_map api_host = client_config_map.gateway.gateway_api_host api_port = client_config_map.gateway.gateway_api_port if GatewayHttpClient.__instance is None: self._base_url = f"https://{api_host}:{api_port}" self._client_confi_map = client_config_map GatewayHttpClient.__instance = self
async def set_up_class(cls): add_files_extension(settings.CONF_FILE_PATH, [".yml", ".json"], ".temp") asyncio.ensure_future(hb_main()) cls.hb = HummingbotApplication.main_application() await wait_til( lambda: ExchangeRateConversion.get_instance()._ready_notifier. is_set(), 20) await wait_til(lambda: 'Enter "config" to create a bot' in cls.hb.app. output_field.document.text)