def test_import_config_file_success(
            self, status_check_all_mock: AsyncMock,
            get_strategy_pydantic_config_cls: MagicMock):
        strategy_name = "perpetual_market_making"
        strategy_file_name = f"{strategy_name}.yml"
        status_check_all_mock.return_value = True
        dummy_strategy_config_cls = self.build_dummy_strategy_config_cls(
            strategy_name)
        get_strategy_pydantic_config_cls.return_value = dummy_strategy_config_cls
        cm = ClientConfigAdapter(
            dummy_strategy_config_cls(no_default="some value"))

        with TemporaryDirectory() as d:
            d = Path(d)
            import_command.STRATEGIES_CONF_DIR_PATH = d
            temp_file_name = d / strategy_file_name
            save_to_yml(temp_file_name, cm)
            self.async_run_with_timeout(
                self.app.import_config_file(strategy_file_name))

        self.assertEqual(strategy_file_name, self.app.strategy_file_name)
        self.assertEqual(strategy_name, self.app.strategy_name)
        self.assertTrue(
            self.cli_mock_assistant.check_log_called_with(
                "\nEnter \"start\" to start market making."))
        self.assertEqual(cm, self.app.strategy_config_map)
def migrate_global_config() -> List[str]:
    global celo_address

    logging.getLogger().info("\nMigrating the global config...")
    global_config_path = CONF_DIR_PATH / "conf_global.yml"
    errors = []
    if global_config_path.exists():
        with open(str(global_config_path), "r") as f:
            data = yaml.safe_load(f)
        del data["template_version"]
        client_config_map = ClientConfigAdapter(ClientConfigMap())
        _migrate_global_config_modes(client_config_map, data)
        data.pop("kraken_api_tier", None)
        data.pop("key_file_path", None)
        celo_address = data.pop("celo_address", None)
        keys = list(data.keys())
        for key in keys:
            if key in client_config_map.keys():
                _migrate_global_config_field(client_config_map, data, key)
        for key in data:
            logging.getLogger().warning(f"Global ConfigVar {key} was not migrated.")
        errors.extend(client_config_map.validate_model())
        if len(errors) == 0:
            save_to_yml(CLIENT_CONFIG_PATH, client_config_map)
            global_config_path.unlink()
            logging.getLogger().info("\nSuccessfully migrated the global config.")
        else:
            errors = [f"client_config_map - {e}" for e in errors]
            logging.getLogger().error(f"The migration of the global config map failed with errors: {errors}")
    return errors
示例#3
0
 async def connect_ethereum(self,  # type: HummingbotApplication
                            ):
     self.placeholder_mode = True
     self.app.hide_input = True
     ether_wallet = global_config_map["ethereum_wallet"].value
     to_connect = True
     if ether_wallet is not None:
         answer = await self.app.prompt(prompt=f"Would you like to replace your existing Ethereum wallet "
                                               f"{ether_wallet} (Yes/No)? >>> ")
         if self.app.to_stop_config:
             self.app.to_stop_config = False
             return
         if answer.lower() not in ("yes", "y"):
             to_connect = False
     if to_connect:
         private_key = await self.app.prompt(prompt="Enter your wallet private key >>> ", is_password=True)
         public_address = Security.add_private_key(private_key)
         global_config_map["ethereum_wallet"].value = public_address
         if global_config_map["ethereum_rpc_url"].value is None:
             await self.prompt_a_config(global_config_map["ethereum_rpc_url"])
         if global_config_map["ethereum_rpc_ws_url"].value is None:
             await self.prompt_a_config(global_config_map["ethereum_rpc_ws_url"])
         if self.app.to_stop_config:
             self.app.to_stop_config = False
             return
         save_to_yml(GLOBAL_CONFIG_PATH, global_config_map)
         err_msg = UserBalances.validate_ethereum_wallet()
         if err_msg is None:
             self._notify(f"Wallet {public_address} connected to hummingbot.")
         else:
             self._notify(f"\nError: {err_msg}")
     self.placeholder_mode = False
     self.app.hide_input = False
     self.app.change_prompt(prompt=">>> ")
示例#4
0
    async def connect_celo(
            self,  # type: HummingbotApplication
    ):
        self.placeholder_mode = True
        self.app.hide_input = True
        celo_address = global_config_map["celo_address"].value
        to_connect = True
        if celo_address is not None:
            answer = await self.app.prompt(
                prompt=
                f"Would you like to replace your existing Celo account address "
                f"{celo_address} (Yes/No)? >>> ")
            if answer.lower() not in ("yes", "y"):
                to_connect = False
        if to_connect:
            await self.prompt_a_config(global_config_map["celo_address"])
            await self.prompt_a_config(global_config_map["celo_password"])
            save_to_yml(settings.GLOBAL_CONFIG_PATH, global_config_map)

            err_msg = await self.validate_n_connect_celo(
                True, global_config_map["celo_address"].value,
                global_config_map["celo_password"].value)
            if err_msg is None:
                self._notify("You are now connected to Celo network.")
            else:
                self._notify(err_msg)
        self.placeholder_mode = False
        self.app.hide_input = False
        self.app.change_prompt(prompt=">>> ")
 def store_binance_config(self) -> ClientConfigAdapter:
     config_map = ClientConfigAdapter(
         BinanceConfigMap(binance_api_key=self.api_key, binance_api_secret=self.api_secret)
     )
     file_path = get_connector_config_yml_path(self.connector)
     save_to_yml(file_path, config_map)
     return config_map
def migrate_xemm_confs(conf, new_path) -> List[str]:
    if "active_order_canceling" in conf:
        if conf["active_order_canceling"]:
            conf["order_refresh_mode"] = {}
        else:
            conf["order_refresh_mode"] = {
                "cancel_order_threshold": conf["cancel_order_threshold"],
                "limit_order_min_expiration": conf["limit_order_min_expiration"]
            }
        conf.pop("active_order_canceling")
        conf.pop("cancel_order_threshold")
        conf.pop("limit_order_min_expiration")
    if "use_oracle_conversion_rate" in conf:
        if conf["use_oracle_conversion_rate"]:
            conf["conversion_rate_mode"] = {}
        else:
            conf["conversion_rate_mode"] = {
                "taker_to_maker_base_conversion_rate": conf["taker_to_maker_base_conversion_rate"],
                "taker_to_maker_quote_conversion_rate": conf["taker_to_maker_quote_conversion_rate"]
            }
        conf.pop("use_oracle_conversion_rate")
        conf.pop("taker_to_maker_base_conversion_rate")
        conf.pop("taker_to_maker_quote_conversion_rate")
    if "template_version" in conf:
        conf.pop("template_version")
    try:
        config_map = ClientConfigAdapter(CrossExchangeMarketMakingConfigMap(**conf))
        save_to_yml(new_path, config_map)
        errors = []
    except Exception as e:
        logging.getLogger().error(str(e))
        errors = [str(e)]
    return errors
示例#7
0
    async def set_paper_balance(self, asset, amount):
        self.app.clear_input()
        self.placeholder_mode = True
        self.app.hide_input = True

        answer = await self.app.prompt(
            prompt=
            "Setting a new paper balance on runtime requires to clear the current trading history. Would you like to do proceed (Yes/No)? >>> "
        )
        if answer.lower() in ("yes", "y"):
            config_map = global_config_map
            file_path = GLOBAL_CONFIG_PATH
            config_var = config_map["paper_trade_account_balance"]
            paper_balances = dict(config_var.value) if config_var.value else {}
            paper_balances[asset] = amount
            config_var.value = paper_balances
            save_to_yml(file_path, config_map)
            self._notify(f"Paper balance for {asset} token set to {amount}")

            # Reset paper trade exchange class account balance to reflect the new balance on strategy start
            reset_paper_trade_account_balance()

            # Set new app init time to clear current trading history because the account balance has changed which will lead to wrong performance calculations
            self._main_app.init_time = time.time()
            self._notify("The trading history has been cleared!")
        else:
            self._notify("Your current paper balance has not been changed!")

        self.app.hide_input = False
        self.placeholder_mode = False
        self.app.change_prompt(prompt=">>> ")
示例#8
0
    async def prompt_for_configuration(self,  # type: HummingbotApplication
                                       file_name):
        self.app.clear_input()
        self.placeholder_mode = True
        self.app.hide_input = True
        required_exchanges.clear()

        strategy_config = ConfigVar(key="strategy",
                                    prompt="What is your market making strategy? >>> ",
                                    validator=validate_strategy)
        await self.prompt_a_config(strategy_config)
        if self.app.to_stop_config:
            self.app.to_stop_config = False
            return
        strategy = strategy_config.value
        config_map = get_strategy_config_map(strategy)
        self._notify(f"Please see https://docs.hummingbot.io/strategies/{strategy.replace('_', '-')}/ "
                     f"while setting up these below configuration.")
        # assign default values and reset those not required
        for config in config_map.values():
            if config.required:
                config.value = config.default
            else:
                config.value = None
        for config in config_map.values():
            if config.prompt_on_new and config.required:
                if not self.app.to_stop_config:
                    await self.prompt_a_config(config)
                else:
                    self.app.to_stop_config = False
                    return
            else:
                config.value = config.default

        # catch a last key binding to stop config, if any
        if self.app.to_stop_config:
            self.app.to_stop_config = False
            return

        if file_name is None:
            file_name = await self.prompt_new_file_name(strategy)
            if self.app.to_stop_config:
                self.app.to_stop_config = False
                self.app.set_text("")
                return
        self.app.change_prompt(prompt=">>> ")
        strategy_path = os.path.join(CONF_FILE_PATH, file_name)
        template = get_strategy_template_path(strategy)
        shutil.copy(template, strategy_path)
        save_to_yml(strategy_path, config_map)
        self.strategy_file_name = file_name
        self.strategy_name = strategy
        # Reload completer here otherwise the new file will not appear
        self.app.input_field.completer = load_completer(self)
        self._notify(f"A new config file {self.strategy_file_name} created.")
        self.placeholder_mode = False
        self.app.hide_input = False
        if await self.status_check_all():
            self._notify("\nEnter \"start\" to start market making.")
示例#9
0
    def balance(self, option: str = None, args: List[str] = None):
        if threading.current_thread() != threading.main_thread():
            self.ev_loop.call_soon_threadsafe(self.balance, option, args)
            return

        self.app.clear_input()
        if option is None:
            safe_ensure_future(self.show_balances())

        elif option in OPTIONS:
            config_map = global_config_map
            file_path = GLOBAL_CONFIG_PATH
            if option == "limit":
                config_var = config_map["balance_asset_limit"]
                if args is None or len(args) == 0:
                    safe_ensure_future(self.show_asset_limits())
                    return
                if len(args) != 3 or validate_exchange(
                        args[0]) is not None or validate_decimal(
                            args[2]) is not None:
                    self._notify("Error: Invalid command arguments")
                    self.notify_balance_limit_set()
                    return
                exchange = args[0]
                asset = args[1].upper()
                amount = float(args[2])
                if exchange not in config_var.value or config_var.value[
                        exchange] is None:
                    config_var.value[exchange] = {}
                if amount < 0 and asset in config_var.value[exchange].keys():
                    config_var.value[exchange].pop(asset)
                    self._notify(
                        f"Limit for {asset} on {exchange} exchange removed.")
                elif amount >= 0:
                    config_var.value[exchange][asset] = amount
                    self._notify(
                        f"Limit for {asset} on {exchange} exchange set to {amount}"
                    )
                save_to_yml(file_path, config_map)

            elif option == "paper":
                config_var = config_map["paper_trade_account_balance"]
                if args is None or len(args) == 0:
                    safe_ensure_future(self.show_paper_account_balance())
                    return
                if len(args) != 2 or validate_decimal(args[1]) is not None:
                    self._notify("Error: Invalid command arguments")
                    self.notify_balance_paper_set()
                    return
                asset = args[0].upper()
                amount = float(args[1])
                paper_balances = dict(
                    config_var.value) if config_var.value else {}
                paper_balances[asset] = amount
                config_var.value = paper_balances
                self._notify(
                    f"Paper balance for {asset} token set to {amount}")
                save_to_yml(file_path, config_map)
示例#10
0
    async def _config_single_key(self,  # type: HummingbotApplication
                                 key: str,
                                 input_value):
        """
        Configure a single variable only.
        Prompt the user to finish all configurations if there are remaining empty configs at the end.
        """

        self.placeholder_mode = True
        self.app.hide_input = True

        try:
            config_var, config_map, file_path = None, None, None
            if key in global_config_map:
                config_map = global_config_map
                file_path = GLOBAL_CONFIG_PATH
            elif self.strategy_config_map is not None and key in self.strategy_config_map:
                config_map = self.strategy_config_map
                file_path = join(CONF_FILE_PATH, self.strategy_file_name)
            config_var = config_map[key]
            if input_value is None:
                self._notify("Please follow the prompt to complete configurations: ")
            if config_var.key == "inventory_target_base_pct":
                await self.asset_ratio_maintenance_prompt(config_map, input_value)
            elif config_var.key == "inventory_price":
                await self.inventory_price_prompt(config_map, input_value)
            else:
                await self.prompt_a_config(config_var, input_value=input_value, assign_default=False)
            if self.app.to_stop_config:
                self.app.to_stop_config = False
                return
            await self.update_all_secure_configs()
            missings = missing_required_configs(config_map)
            if missings:
                self._notify("\nThere are other configuration required, please follow the prompt to complete them.")
            missings = await self._prompt_missing_configs(config_map)
            save_to_yml(file_path, config_map)
            self._notify("\nNew configuration saved:")
            self._notify(f"{key}: {str(config_var.value)}")
            for config in missings:
                self._notify(f"{config.key}: {str(config.value)}")
            if isinstance(self.strategy, PureMarketMakingStrategy) or \
               isinstance(self.strategy, PerpetualMarketMakingStrategy):
                updated = ConfigCommand.update_running_mm(self.strategy, key, config_var.value)
                if updated:
                    self._notify(f"\nThe current {self.strategy_name} strategy has been updated "
                                 f"to reflect the new configuration.")
        except asyncio.TimeoutError:
            self.logger().error("Prompt timeout")
        except Exception as err:
            self.logger().error(str(err), exc_info=True)
        finally:
            self.app.hide_input = False
            self.placeholder_mode = False
            self.app.change_prompt(prompt=">>> ")
示例#11
0
 async def save_config_to_file(
     self,  # type: HummingbotApplication
     file_name: Optional[str],
     config_map: ClientConfigAdapter,
 ) -> str:
     if file_name is None:
         file_name = await self.prompt_new_file_name(config_map.strategy)
         if self.app.to_stop_config:
             self.app.set_text("")
             return
     self.app.change_prompt(prompt=">>> ")
     strategy_path = Path(STRATEGIES_CONF_DIR_PATH) / file_name
     save_to_yml(strategy_path, config_map)
     return file_name
示例#12
0
def reset_style(config_map=global_config_map, save=True):
    # Reset config
    config_map.get("top-pane").value = config_map.get("top-pane").default
    config_map.get("bottom-pane").value = config_map.get("bottom-pane").default
    config_map.get("output-pane").value = config_map.get("output-pane").default
    config_map.get("input-pane").value = config_map.get("input-pane").default
    config_map.get("logs-pane").value = config_map.get("logs-pane").default
    config_map.get("terminal-primary").value = config_map.get(
        "terminal-primary").default

    # Save configuration
    if save:
        file_path = GLOBAL_CONFIG_PATH
        save_to_yml(file_path, config_map)

    # Apply & return style
    return load_style(config_map)
def migrate_amm_confs(conf, new_path) -> List[str]:
    execution_timeframe = conf.pop("execution_timeframe")
    if execution_timeframe == "infinite":
        conf["execution_timeframe_mode"] = {}
        conf.pop("start_time")
        conf.pop("end_time")
    elif execution_timeframe == "from_date_to_date":
        conf["execution_timeframe_mode"] = {
            "start_datetime": conf.pop("start_time"),
            "end_datetime": conf.pop("end_time"),
        }
    else:
        assert execution_timeframe == "daily_between_times"
        conf["execution_timeframe_mode"] = {
            "start_time": conf.pop("start_time"),
            "end_time": conf.pop("end_time"),
        }
    order_levels = int(conf.pop("order_levels"))
    if order_levels == 1:
        conf["order_levels_mode"] = {}
        conf.pop("level_distances")
    else:
        conf["order_levels_mode"] = {
            "order_levels": order_levels,
            "level_distances": conf.pop("level_distances")
        }
    hanging_orders_enabled = conf.pop("hanging_orders_enabled")
    if not hanging_orders_enabled:
        conf["hanging_orders_mode"] = {}
        conf.pop("hanging_orders_cancel_pct")
    else:
        conf["hanging_orders_mode"] = {
            "hanging_orders_cancel_pct": conf.pop("hanging_orders_cancel_pct")
        }
    if "template_version" in conf:
        conf.pop("template_version")
    try:
        config_map = ClientConfigAdapter(AvellanedaMarketMakingConfigMap(**conf))
        save_to_yml(new_path, config_map)
        errors = []
    except Exception as e:
        logging.getLogger().error(str(e))
        errors = [str(e)]
    return errors
示例#14
0
    def test_load_connector_config_map_from_file_with_secrets(
            self, get_connector_config_keys_mock: MagicMock):
        class DummyConnectorModel(BaseConnectorConfigMap):
            connector = "some-connector"
            secret_attr: Optional[SecretStr] = Field(default=None)

        password = "******"
        Security.secrets_manager = ETHKeyFileSecretManger(password)
        cm = ClientConfigAdapter(
            DummyConnectorModel(secret_attr="some_secret"))
        get_connector_config_keys_mock.return_value = DummyConnectorModel()
        with TemporaryDirectory() as d:
            d = Path(d)
            config_helpers.CONNECTORS_CONF_DIR_PATH = d
            temp_file_name = get_connector_config_yml_path(cm.connector)
            save_to_yml(temp_file_name, cm)
            cm_loaded = load_connector_config_map_from_file(temp_file_name)

        self.assertEqual(cm, cm_loaded)
示例#15
0
    def test_save_command_shortcuts_to_yml(self):
        class DummyStrategy(BaseClientModel):
            command_shortcuts: List[CommandShortcutModel] = Field(default=[
                CommandShortcutModel(
                    command="spreads",
                    help="Set bid and ask spread",
                    arguments=["Bid Spread", "Ask Spread"],
                    output=["config bid_spread $1", "config ask_spread $2"])
            ])
            another_attr: Decimal = Field(
                default=Decimal("1.0"),
                description="Some other\nmultiline description",
            )

            class Config:
                title = "dummy_global_config"

        cm = ClientConfigAdapter(DummyStrategy())
        expected_str = ("######################################\n"
                        "###   dummy_global_config config   ###\n"
                        "######################################\n\n"
                        "command_shortcuts:\n"
                        "- command: spreads\n"
                        "  help: Set bid and ask spread\n"
                        "  arguments:\n"
                        "  - Bid Spread\n"
                        "  - Ask Spread\n"
                        "  output:\n"
                        "  - config bid_spread $1\n"
                        "  - config ask_spread $2\n\n"
                        "# Some other\n"
                        "# multiline description\n"
                        "another_attr: 1.0\n")

        with TemporaryDirectory() as d:
            d = Path(d)
            temp_file_name = d / "cm.yml"
            save_to_yml(temp_file_name, cm)
            with open(temp_file_name) as f:
                actual_str = f.read()
        self.assertEqual(expected_str, actual_str)
示例#16
0
    def test_save_to_yml(self):
        class DummyStrategy(BaseStrategyConfigMap):
            class Config:
                title = "pure_market_making"

            strategy: str = "pure_market_making"

        cm = ClientConfigAdapter(DummyStrategy())
        expected_str = """\
#####################################
###   pure_market_making config   ###
#####################################

strategy: pure_market_making
"""
        with TemporaryDirectory() as d:
            d = Path(d)
            temp_file_name = d / "cm.yml"
            save_to_yml(temp_file_name, cm)
            with open(temp_file_name) as f:
                actual_str = f.read()
        self.assertEqual(expected_str, actual_str)
示例#17
0
def reset_style(config_map: ClientConfigAdapter, save=True):
    # Reset config

    config_map.color.top_pane = config_map.color.get_default("top_pane")
    config_map.color.bottom_pane = config_map.color.get_default("bottom_pane")
    config_map.color.output_pane = config_map.color.get_default("output_pane")
    config_map.color.input_pane = config_map.color.get_default("input_pane")
    config_map.color.logs_pane = config_map.color.get_default("logs_pane")
    config_map.color.terminal_primary = config_map.color.get_default("terminal_primary")

    config_map.color.primary_label = config_map.color.get_default("primary_label")
    config_map.color.secondary_label = config_map.color.get_default("secondary_label")
    config_map.color.success_label = config_map.color.get_default("success_label")
    config_map.color.warning_label = config_map.color.get_default("warning_label")
    config_map.color.info_label = config_map.color.get_default("info_label")
    config_map.color.error_label = config_map.color.get_default("error_label")

    # Save configuration
    if save:
        save_to_yml(CLIENT_CONFIG_PATH, config_map)

    # Apply & return style
    return load_style(config_map)
示例#18
0
    async def _config_single_key(
            self,  # type: HummingbotApplication
            key: str,
            input_value):
        """
        Configure a single variable only.
        Prompt the user to finish all configurations if there are remaining empty configs at the end.
        """

        self.placeholder_mode = True
        self.app.hide_input = True

        try:
            if (not isinstance(self.strategy_config_map,
                               (type(None), ClientConfigAdapter))
                    and key in self.strategy_config_map):
                await self._config_single_key_legacy(key, input_value)
            else:
                client_config_key = key in self.client_config_map.config_paths(
                )
                if client_config_key:
                    config_map = self.client_config_map
                    file_path = CLIENT_CONFIG_PATH
                elif self.strategy is not None:
                    self.notify(
                        "Configuring the strategy while it is running is not currently supported."
                    )
                    return
                else:
                    config_map = self.strategy_config_map
                    file_path = STRATEGIES_CONF_DIR_PATH / self.strategy_file_name
                if input_value is None:
                    self.notify(
                        "Please follow the prompt to complete configurations: "
                    )
                if key == "inventory_target_base_pct":
                    await self.asset_ratio_maintenance_prompt(
                        config_map, input_value)
                elif key == "inventory_price":
                    await self.inventory_price_prompt(config_map, input_value)
                else:
                    await self.prompt_a_config(config_map,
                                               key,
                                               input_value,
                                               assign_default=False)
                if self.app.to_stop_config:
                    self.app.to_stop_config = False
                    return
                save_to_yml(file_path, config_map)
                self.notify("\nNew configuration saved.")
                if client_config_key:
                    self.list_client_configs()
                else:
                    self.list_strategy_configs()
                self.app.app.style = load_style(self.client_config_map)
        except asyncio.TimeoutError:
            self.logger().error("Prompt timeout")
        except Exception as err:
            self.logger().error(str(err), exc_info=True)
        finally:
            self.app.hide_input = False
            self.placeholder_mode = False
            self.app.change_prompt(prompt=">>> ")
示例#19
0
    async def _create_gateway(self):
        gateway_paths: GatewayPaths = get_gateway_paths()
        gateway_container_name: str = get_gateway_container_name()
        gateway_conf_mount_path: str = gateway_paths.mount_conf_path.as_posix()
        certificate_mount_path: str = gateway_paths.mount_certs_path.as_posix()
        logs_mount_path: str = gateway_paths.mount_logs_path.as_posix()
        gateway_port: int = get_default_gateway_port()

        # remove existing container(s)
        try:
            old_container = await docker_ipc(
                "containers",
                all=True,
                filters={"name": gateway_container_name}
            )
            for container in old_container:
                self.notify(f"Removing existing gateway container with id {container['Id']}...")
                await docker_ipc(
                    "remove_container",
                    container["Id"],
                    force=True
                )
        except Exception:
            pass  # silently ignore exception

        await self._generate_certs(from_client_password=True)  # create cert

        if await self.check_gateway_image(GATEWAY_DOCKER_REPO, GATEWAY_DOCKER_TAG):
            self.notify("Found Gateway docker image. No image pull needed.")
        else:
            self.notify("Pulling Gateway docker image...")
            try:
                await self.pull_gateway_docker(GATEWAY_DOCKER_REPO, GATEWAY_DOCKER_TAG)
                self.logger().info("Done pulling Gateway docker image.")
            except Exception as e:
                self.notify("Error pulling Gateway docker image. Try again.")
                self.logger().network("Error pulling Gateway docker image. Try again.",
                                      exc_info=True,
                                      app_warning_msg=str(e))
                return
        self.notify("Creating new Gateway docker container...")
        host_config: Dict[str, Any] = await docker_ipc(
            "create_host_config",
            port_bindings={5000: gateway_port},
            binds={
                gateway_conf_mount_path: {
                    "bind": "/usr/src/app/conf/",
                    "mode": "rw"
                },
                certificate_mount_path: {
                    "bind": "/usr/src/app/certs/",
                    "mode": "rw"
                },
                logs_mount_path: {
                    "bind": "/usr/src/app/logs/",
                    "mode": "rw"
                },
            }
        )
        container_info: Dict[str, str] = await docker_ipc(
            "create_container",
            image=f"{GATEWAY_DOCKER_REPO}:{GATEWAY_DOCKER_TAG}",
            name=gateway_container_name,
            ports=[5000],
            volumes=[
                gateway_conf_mount_path,
                certificate_mount_path,
                logs_mount_path
            ],
            host_config=host_config,
            environment=[f"GATEWAY_PASSPHRASE={Security.password}"]
        )

        self.notify(f"New Gateway docker container id is {container_info['Id']}.")

        # Save the gateway port number, if it's not already there.
        if global_config_map.get("gateway_api_port").value != gateway_port:
            global_config_map["gateway_api_port"].value = gateway_port
            global_config_map["gateway_api_host"].value = "localhost"
            save_to_yml(GLOBAL_CONFIG_PATH, global_config_map)

        GatewayHttpClient.get_instance().base_url = f"https://{global_config_map['gateway_api_host'].value}:" \
                                                    f"{global_config_map['gateway_api_port'].value}"
        await start_gateway()

        # create Gateway configs
        await self._generate_gateway_confs(container_id=container_info["Id"])

        # Restarts the Gateway container to ensure that Gateway server reloads new configs
        try:
            await docker_ipc(method_name="restart",
                             container=container_info["Id"])
        except docker.errors.APIError as e:
            self.notify(f"Error restarting Gateway container. Error: {e}")

        self.notify(f"Loaded new configs into Gateway container {container_info['Id']}")
示例#20
0
 def update_secure_config(cls, connector_config: ClientConfigAdapter):
     connector_name = connector_config.connector
     file_path = get_connector_config_yml_path(connector_name)
     save_to_yml(file_path, connector_config)
     update_connector_hb_config(connector_config)
     cls._secure_configs[connector_name] = connector_config
示例#21
0
    async def prompt_for_configuration(
            self,  # type: HummingbotApplication
            file_name):
        self.app.clear_input()
        self.placeholder_mode = True
        self.app.hide_input = True
        required_exchanges.clear()

        strategy_config = ConfigVar(
            key="strategy",
            prompt="What is your market making strategy? >>> ",
            validator=validate_strategy)
        await self.prompt_a_config(strategy_config)
        if self.app.to_stop_config:
            self.stop_config()
            return
        strategy = strategy_config.value
        config_map = get_strategy_config_map(strategy)
        config_map_backup = copy.deepcopy(config_map)
        self._notify(
            f"Please see https://docs.hummingbot.io/strategies/{strategy.replace('_', '-')}/ "
            f"while setting up these below configuration.")
        # assign default values and reset those not required
        for config in config_map.values():
            if config.required:
                config.value = config.default
            else:
                config.value = None
        for config in config_map.values():
            if config.prompt_on_new and config.required:
                if not self.app.to_stop_config:
                    await self.prompt_a_config(config)
                else:
                    break
            else:
                config.value = config.default

        if self.app.to_stop_config:
            self.stop_config(config_map, config_map_backup)
            return

        if file_name is None:
            file_name = await self.prompt_new_file_name(strategy)
            if self.app.to_stop_config:
                self.stop_config(config_map, config_map_backup)
                self.app.set_text("")
                return
        self.app.change_prompt(prompt=">>> ")
        strategy_path = os.path.join(CONF_FILE_PATH, file_name)
        template = get_strategy_template_path(strategy)
        shutil.copy(template, strategy_path)
        save_to_yml(strategy_path, config_map)
        self.strategy_file_name = file_name
        self.strategy_name = strategy
        # Reload completer here otherwise the new file will not appear
        self.app.input_field.completer = load_completer(self)
        self._notify(f"A new config file {self.strategy_file_name} created.")
        self.placeholder_mode = False
        self.app.hide_input = False
        try:
            timeout = float(global_config_map["create_command_timeout"].value)
            all_status_go = await asyncio.wait_for(self.status_check_all(),
                                                   timeout)
        except asyncio.TimeoutError:
            self._notify(
                "\nA network error prevented the connection check to complete. See logs for more details."
            )
            self.strategy_file_name = None
            self.strategy_name = None
            raise
        if all_status_go:
            self._notify("\nEnter \"start\" to start market making.")
示例#22
0
 def save_client_config(self):
     save_to_yml(CLIENT_CONFIG_PATH, self.client_config_map)
示例#23
0
    async def _create_gateway(
        self  # type: HummingbotApplication
    ):
        gateway_paths: GatewayPaths = get_gateway_paths(self.client_config_map)
        gateway_container_name: str = get_gateway_container_name(self.client_config_map)
        gateway_conf_mount_path: str = gateway_paths.mount_conf_path.as_posix()
        certificate_mount_path: str = gateway_paths.mount_certs_path.as_posix()
        logs_mount_path: str = gateway_paths.mount_logs_path.as_posix()
        gateway_port: int = get_default_gateway_port(self.client_config_map)

        # remove existing container(s)
        try:
            old_container = await docker_ipc(
                "containers",
                all=True,
                filters={"name": gateway_container_name}
            )
            for container in old_container:
                self.notify(f"Removing existing gateway container with id {container['Id']}...")
                await docker_ipc(
                    "remove_container",
                    container["Id"],
                    force=True
                )
        except Exception:
            pass  # silently ignore exception

        await self._generate_certs(from_client_password=True)  # create cert

        if await self.check_gateway_image(GATEWAY_DOCKER_REPO, GATEWAY_DOCKER_TAG):
            self.notify("Found Gateway docker image. No image pull needed.")
        else:
            self.notify("Pulling Gateway docker image...")
            try:
                await self.pull_gateway_docker(GATEWAY_DOCKER_REPO, GATEWAY_DOCKER_TAG)
                self.logger().info("Done pulling Gateway docker image.")
            except Exception as e:
                self.notify("Error pulling Gateway docker image. Try again.")
                self.logger().network("Error pulling Gateway docker image. Try again.",
                                      exc_info=True,
                                      app_warning_msg=str(e))
                return
        self.notify("Creating new Gateway docker container...")
        host_config: Dict[str, Any] = await docker_ipc(
            "create_host_config",
            port_bindings={5000: gateway_port},
            binds={
                gateway_conf_mount_path: {
                    "bind": "/usr/src/app/conf/",
                    "mode": "rw"
                },
                certificate_mount_path: {
                    "bind": "/usr/src/app/certs/",
                    "mode": "rw"
                },
                logs_mount_path: {
                    "bind": "/usr/src/app/logs/",
                    "mode": "rw"
                },
            }
        )
        container_info: Dict[str, str] = await docker_ipc(
            "create_container",
            image=f"{GATEWAY_DOCKER_REPO}:{GATEWAY_DOCKER_TAG}",
            name=gateway_container_name,
            ports=[5000],
            volumes=[
                gateway_conf_mount_path,
                certificate_mount_path,
                logs_mount_path
            ],
            host_config=host_config,
            environment=[f"GATEWAY_PASSPHRASE={Security.secrets_manager.password.get_secret_value()}"]
        )

        self.notify(f"New Gateway docker container id is {container_info['Id']}.")

        # Save the gateway port number, if it's not already there.
        gateway_config_map = self.client_config_map.gateway
        if gateway_config_map.gateway_api_port != gateway_port:
            gateway_config_map.gateway_api_port = gateway_port
            gateway_config_map.gateway_api_host = "localhost"
            save_to_yml(CLIENT_CONFIG_PATH, self.client_config_map)

        self._get_gateway_instance().base_url = (
            f"https://{gateway_config_map.gateway_api_host}:{gateway_config_map.gateway_api_port}"
        )
        await start_gateway(self.client_config_map)

        # create Gateway configs
        await self._generate_gateway_confs(container_id=container_info["Id"])

        self.notify("Gateway is starting, please wait a moment.")
        # wait about 30 seconds for the gateway to start
        docker_and_gateway_live = await self.ping_gateway_docker_and_api(30)
        if docker_and_gateway_live:
            self.notify("Gateway has started succesfully.")
        else:
            self.notify("Error starting Gateway container.")