def update_connector_hb_config(connector_config: ClientConfigAdapter): connector_name = connector_config.connector if connector_name == "celo": celo_data_types.KEYS = connector_config.hb_config else: AllConnectorSettings.update_connector_config_keys( connector_config.hb_config)
def validate_exchange(cls, v: str, field: Field): """Used for client-friendly error output.""" ret = validate_exchange(v) if ret is not None: raise ValueError(ret) if field.name == "maker_market_trading_pair": cls.__fields__[ "maker_market"].type_ = ClientConfigEnum( # rebuild the exchanges enum value="Exchanges", # noqa: F821 names={ e: e for e in AllConnectorSettings.get_connector_settings().keys() }, type=str, ) if field.name == "taker_market_trading_pair": cls.__fields__[ "taker_market"].type_ = ClientConfigEnum( # rebuild the exchanges enum value="Exchanges", # noqa: F821 names={ e: e for e in AllConnectorSettings.get_connector_settings().keys() }, type=str, ) return v
async def update_exchanges( self, client_config_map: ClientConfigMap, reconnect: bool = False, exchanges: Optional[List[str]] = None) -> Dict[str, Optional[str]]: exchanges = exchanges or [] tasks = [] # Update user balances if len(exchanges) == 0: exchanges = [ cs.name for cs in AllConnectorSettings.get_connector_settings().values() ] exchanges: List[str] = [ cs.name for cs in AllConnectorSettings.get_connector_settings().values() if not cs.use_ethereum_wallet and cs.name in exchanges and not cs.name.endswith("paper_trade") ] if reconnect: self._markets.clear() for exchange in exchanges: tasks.append( self.update_exchange_balance(exchange, client_config_map)) results = await safe_gather(*tasks) return {ex: err_msg for ex, err_msg in zip(exchanges, results)}
def build_perpetual_trade_fee( exchange: str, is_maker: bool, position_action: PositionAction, base_currency: str, quote_currency: str, order_type: OrderType, order_side: TradeType, amount: Decimal, price: Decimal = Decimal("NaN"), ) -> TradeFeeBase: """ WARNING: Do not use this method for order sizing. Use the `BudgetChecker` instead. Uses the exchange's `TradeFeeSchema` to build a `TradeFee`, given the trade parameters. """ if exchange not in AllConnectorSettings.get_connector_settings(): raise Exception( f"Invalid connector. {exchange} does not exist in AllConnectorSettings" ) trade_fee_schema = AllConnectorSettings.get_connector_settings( )[exchange].trade_fee_schema trade_fee_schema = _superimpose_overrides(exchange, trade_fee_schema) percent = trade_fee_schema.maker_percent_fee_decimal if is_maker else trade_fee_schema.taker_percent_fee_decimal fee_cls = (AddedToCostTradeFee if position_action == PositionAction.OPEN or trade_fee_schema.percent_fee_token is not None else DeductedFromReturnsTradeFee) fixed_fees = trade_fee_schema.maker_fixed_fees if is_maker else trade_fee_schema.taker_fixed_fees trade_fee = fee_cls(percent, trade_fee_schema.percent_fee_token, fixed_fees) return trade_fee
async def quote_in_eth_rate_fetch_loop(self): while True: try: if self._market_info_1.market.name in AllConnectorSettings.get_eth_wallet_connector_names() and \ "WETH" not in self._market_info_1.trading_pair.split("-"): self._market_1_quote_eth_rate = await self.request_rate_in_eth( self._market_info_1.quote_asset) self.logger().warning( f"Estimate conversion rate - " f"{self._market_info_1.quote_asset}:ETH = {self._market_1_quote_eth_rate} " ) if self._market_info_2.market.name in AllConnectorSettings.get_eth_wallet_connector_names() and \ "WETH" not in self._market_info_2.trading_pair.split("-"): self._market_2_quote_eth_rate = await self.request_rate_in_eth( self._market_info_2.quote_asset) self.logger().warning( f"Estimate conversion rate - " f"{self._market_info_2.quote_asset}:ETH = {self._market_2_quote_eth_rate} " ) await asyncio.sleep(60 * 1) except asyncio.CancelledError: raise except Exception as e: self.logger().error(str(e), exc_info=True) self.logger().network( "Unexpected error while fetching ETH conversion rate.", exc_info=True, app_warning_msg= "Could not fetch ETH conversion rate from Gateway API.") await asyncio.sleep(0.5)
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)
def configured_schema_for_exchange(cls, exchange_name: str) -> TradeFeeSchema: if exchange_name not in AllConnectorSettings.get_connector_settings(): raise Exception( f"Invalid connector. {exchange_name} does not exist in AllConnectorSettings" ) trade_fee_schema = AllConnectorSettings.get_connector_settings( )[exchange_name].trade_fee_schema trade_fee_schema = cls._superimpose_overrides(exchange_name, trade_fee_schema) return trade_fee_schema
async def quick_start(args: argparse.Namespace, secrets_manager: BaseSecretsManager): config_file_name = args.config_file_name client_config = load_client_config_map_from_file() if args.auto_set_permissions is not None: autofix_permissions(args.auto_set_permissions) if not Security.login(secrets_manager): logging.getLogger().error("Invalid password.") return await Security.wait_til_decryption_done() await create_yml_files_legacy() init_logging("hummingbot_logs.yml", client_config) await read_system_configs_from_yml() AllConnectorSettings.initialize_paper_trade_settings( client_config.paper_trade.paper_trade_exchanges) hb = HummingbotApplication.main_application() # Todo: validate strategy and config_file_name before assinging strategy_config = None if config_file_name is not None: hb.strategy_file_name = config_file_name strategy_config = await load_strategy_config_map_from_file( STRATEGIES_CONF_DIR_PATH / config_file_name) hb.strategy_name = (strategy_config.strategy if isinstance( strategy_config, BaseStrategyConfigMap) else strategy_config.get("strategy").value) hb.strategy_config_map = strategy_config if strategy_config is not None: if not all_configs_complete(strategy_config, hb.client_config_map): hb.status() # 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) ] if client_config.debug_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") await read_system_configs_from_yml() AllConnectorSettings.initialize_paper_trade_settings( global_config_map.get("paper_trade_exchanges").value) 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 = await 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() # 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()] 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)
def trading_pair_prompt( cls, model_instance: 'BaseTradingStrategyMakerTakerConfigMap', is_maker: bool) -> str: if is_maker: exchange = model_instance.maker_market example = AllConnectorSettings.get_example_pairs().get(exchange) market_type = "maker" else: exchange = model_instance.taker_market example = AllConnectorSettings.get_example_pairs().get(exchange) market_type = "taker" return ( f"Enter the token trading pair you would like to trade on {market_type} market:" f" {exchange}{f' (e.g. {example})' if example else ''}")
def validate_exchange(value: str) -> Optional[str]: """ Restrict valid exchanges to the exchange file names """ from hummingbot.client.settings import AllConnectorSettings if value not in AllConnectorSettings.get_exchange_names(): return f"Invalid exchange, please choose value from {AllConnectorSettings.get_exchange_names()}"
async def get_last_price(exchange: str, trading_pair: str) -> Optional[Decimal]: if exchange in AllConnectorSettings.get_connector_settings(): conn_setting = AllConnectorSettings.get_connector_settings()[exchange] if AllConnectorSettings.get_connector_settings()[exchange].type in (ConnectorType.Exchange, ConnectorType.Derivative): module_name = f"{conn_setting.base_name()}_api_order_book_data_source" class_name = "".join([o.capitalize() for o in conn_setting.base_name().split("_")]) + \ "APIOrderBookDataSource" module_path = f"hummingbot.connector.{conn_setting.type.name.lower()}." \ f"{conn_setting.base_name()}.{module_name}" module = getattr(importlib.import_module(module_path), class_name) args = {"trading_pairs": [trading_pair]} if conn_setting.is_sub_domain: args["domain"] = conn_setting.domain_parameter last_prices = await module.get_last_traded_prices(**args) if last_prices: return Decimal(str(last_prices[trading_pair]))
def _initialize_markets(self, market_names: List[Tuple[str, List[str]]]): # aggregate trading_pairs if there are duplicate markets for market_name, trading_pairs in market_names: if market_name not in self.market_trading_pairs_map: self.market_trading_pairs_map[market_name] = [] for hb_trading_pair in trading_pairs: self.market_trading_pairs_map[market_name].append(hb_trading_pair) for connector_name, trading_pairs in self.market_trading_pairs_map.items(): conn_setting = AllConnectorSettings.get_connector_settings()[connector_name] if connector_name.endswith("paper_trade") and conn_setting.type == ConnectorType.Exchange: connector = create_paper_trade_market(conn_setting.parent_name, self.client_config_map, trading_pairs) paper_trade_account_balance = self.client_config_map.paper_trade.paper_trade_account_balance if paper_trade_account_balance is not None: for asset, balance in paper_trade_account_balance.items(): connector.set_balance(asset, balance) else: keys = Security.api_keys(connector_name) init_params = conn_setting.conn_init_parameters(keys) init_params.update(trading_pairs=trading_pairs, trading_required=self._trading_required) connector_class = get_connector_class(connector_name) read_only_config = ReadOnlyClientConfigAdapter.lock_config(self.client_config_map) connector = connector_class(read_only_config, **init_params) self.markets[connector_name] = connector 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_market_prompt(self): example = AllConnectorSettings.get_example_pairs().get("uniswap_v3") prompt = market_prompt() expected = f"Enter the trading pair you would like to provide liquidity on (e.g. {example}) >>> " self.assertEqual(expected, prompt)
async def get_last_price(exchange: str, trading_pair: str) -> Optional[Decimal]: if exchange in AllConnectorSettings.get_connector_settings(): conn_setting = AllConnectorSettings.get_connector_settings()[exchange] if AllConnectorSettings.get_connector_settings()[exchange].type in [ ConnectorType.Exchange, ConnectorType.Derivative ]: try: connector = conn_setting.non_trading_connector_instance_with_default_configuration( ) last_prices = await connector.get_last_traded_prices( trading_pairs=[trading_pair]) if last_prices: return Decimal(str(last_prices[trading_pair])) except ModuleNotFoundError: pass
def validate_connector(value: str) -> Optional[str]: """ Restrict valid derivatives to the connector file names """ from hummingbot.client.settings import AllConnectorSettings if value not in AllConnectorSettings.get_connector_settings() and value != "celo": return f"Invalid connector, please choose value from {AllConnectorSettings.get_connector_settings().keys()}"
def validate_derivative(value: str) -> Optional[str]: """ restrict valid derivatives to the derivative file names """ from hummingbot.client.settings import AllConnectorSettings if value not in AllConnectorSettings.get_derivative_names(): return f"Invalid derivative, please choose value from {AllConnectorSettings.get_derivative_names()}"
def fee_overrides_dict(): all_dict = {} # all_connector_types = get_exchanges_and_derivatives() for name in AllConnectorSettings.get_connector_settings().keys(): all_dict.update({ f"{name}_percent_fee_token": new_fee_config_var(f"{name}_percent_fee_token", type_str="str") }) all_dict.update({ f"{name}_maker_percent_fee": new_fee_config_var(f"{name}_maker_percent_fee", type_str="decimal") }) all_dict.update({ f"{name}_taker_percent_fee": new_fee_config_var(f"{name}_taker_percent_fee", type_str="decimal") }) fee_application = f"{name}_buy_percent_fee_deducted_from_returns" all_dict.update({ fee_application: new_fee_config_var(fee_application, type_str="bool") }) all_dict.update({ f"{name}_maker_fixed_fees": new_fee_config_var(f"{name}_maker_fixed_fees", type_str="list") }) all_dict.update({ f"{name}_taker_fixed_fees": new_fee_config_var(f"{name}_taker_fixed_fees", type_str="list") }) return all_dict
def get_connector_hb_config(connector_name: str) -> BaseClientModel: if connector_name == "celo": hb_config = celo_data_types.KEYS else: hb_config = AllConnectorSettings.get_connector_config_keys( connector_name) return hb_config
def connector_keys(): from hummingbot.client.settings import AllConnectorSettings all_keys = {} for connector_setting in AllConnectorSettings.get_connector_settings( ).values(): all_keys.update(connector_setting.config_keys) return all_keys
async def get_current_balances( self, # type: HummingbotApplication market: str): if market in self.markets and self.markets[market].ready: return self.markets[market].get_all_balances() elif "Paper" in market: paper_balances = global_config_map[ "paper_trade_account_balance"].value if paper_balances is None: return {} return { token: Decimal(str(bal)) for token, bal in paper_balances.items() } elif "perpetual_finance" == market: return await UserBalances.xdai_balances() else: gateway_eth_connectors = [ cs.name for cs in AllConnectorSettings.get_connector_settings().values() if cs.use_ethereum_wallet and cs.type == ConnectorType.Connector ] if market in gateway_eth_connectors: return await UserBalances.instance().eth_n_erc20_balances() else: await UserBalances.instance().update_exchange_balance(market) return UserBalances.instance().all_balances(market)
async def fetch_all(self): for conn_setting in AllConnectorSettings.get_connector_settings( ).values(): if conn_setting.base_name().endswith("paper_trade"): if conn_setting.parent_name in self.trading_pairs: self.trading_pairs[conn_setting.base_name( )] = self.trading_pairs[conn_setting.parent_name] continue exchange_name = conn_setting.parent_name else: exchange_name = conn_setting.base_name() module_name = f"{exchange_name}_connector" if conn_setting.type is ConnectorType.Connector \ else f"{exchange_name}_api_order_book_data_source" module_path = f"hummingbot.connector.{conn_setting.type.name.lower()}." \ f"{exchange_name}.{module_name}" class_name = "".join([o.capitalize() for o in exchange_name.split("_")]) + \ "APIOrderBookDataSource" if conn_setting.type is not ConnectorType.Connector \ else "".join([o.capitalize() for o in exchange_name.split("_")]) + "Connector" module = getattr(importlib.import_module(module_path), class_name) args = {} args = conn_setting.add_domain_parameter(args) safe_ensure_future( self.call_fetch_pairs(module.fetch_trading_pairs(**args), conn_setting.name)) self.ready = True
async def api_keys(cls, exchange): await cls.wait_til_decryption_done() exchange_configs = [ c for c in global_config_map.values() if c.key in AllConnectorSettings.get_connector_settings() [exchange].config_keys and c.key in cls._secure_configs ] return {c.key: cls.decrypted_value(c.key) for c in exchange_configs}
def test_maker_trading_pair_prompt(self): pmm_config_map["exchange"].value = self.exchange example = AllConnectorSettings.get_example_pairs().get(self.exchange) prompt = maker_trading_pair_prompt() expected = f"Enter the token trading pair you would like to trade on {self.exchange} (e.g. {example}) >>> " self.assertEqual(expected, prompt)
def test_trading_pair_prompt(self): dev_1_get_order_book_config_map["exchange"].value = self.exchange example = AllConnectorSettings.get_example_pairs().get(self.exchange) prompt = trading_pair_prompt() expected = f"Enter the token trading pair to fetch its order book on {self.exchange} (e.g. {example}) >>> " self.assertEqual(expected, prompt)
def test_symbol_prompt(self): dev_5_vwap_config_map["exchange"].value = self.exchange example = AllConnectorSettings.get_example_pairs().get(self.exchange) prompt = symbol_prompt() expected = f"Enter the trading pair you would like to trade on {self.exchange} (e.g. {example}) >>> " self.assertEqual(expected, prompt)
def get_order_book_tracker(connector_name: str, trading_pairs: List[str]) -> OrderBookTracker: conn_setting = AllConnectorSettings.get_connector_settings()[connector_name] try: connector_instance = conn_setting.non_trading_connector_instance_with_default_configuration( trading_pairs=trading_pairs) return connector_instance.order_book_tracker except Exception as exception: raise Exception(f"Connector {connector_name} OrderBookTracker class not found ({exception})")
def test_asset_prompt(self): dev_0_hello_world_config_map["exchange"].value = self.exchange example = AllConnectorSettings.get_example_assets().get(self.exchange) prompt = asset_prompt() expected = f"Enter a single token to fetch its balance on {self.exchange} (e.g. {example}) >>> " self.assertEqual(expected, prompt)
def connect_market(exchange, **api_details): connector = None conn_setting = AllConnectorSettings.get_connector_settings()[exchange] if not conn_setting.use_ethereum_wallet: connector_class = get_connector_class(exchange) init_params = conn_setting.conn_init_parameters(api_details) connector = connector_class(**init_params) return connector
def create_paper_trade_market(exchange_name: str, trading_pairs: List[str]): obt_class = get_order_book_tracker_class(exchange_name) conn_setting = AllConnectorSettings.get_connector_settings()[exchange_name] obt_params = {"trading_pairs": trading_pairs} obt_kwargs = conn_setting.add_domain_parameter(obt_params) obt_obj = obt_class(**obt_kwargs) return PaperTradeExchange(obt_obj, get_connector_class(exchange_name))