async def reset_config_loop(self, # type: HummingbotApplication key: str = None): strategy = in_memory_config_map.get("strategy").value strategy_cm = get_strategy_config_map(strategy) self.placeholder_mode = True self.app.toggle_hide_input() if self.strategy: choice = await self.app.prompt(prompt=f"Would you like to stop running the {strategy} strategy " f"and reconfigure the bot? (y/n) >>> ") else: choice = await self.app.prompt(prompt=f"Would you like to reconfigure the bot? (y/n) >>> ") self.app.change_prompt(prompt=">>> ") self.app.toggle_hide_input() self.placeholder_mode = False if choice.lower() in {"y", "yes"}: if self.strategy: await self.stop_loop() if key is None: # Clear original strategy config map if strategy_cm: for k in strategy_cm: strategy_cm[k].value = None in_memory_config_map.get("strategy").value = None in_memory_config_map.get("strategy_file_path").value = None self.clear_application_warning() self.config(key) else: self._notify("Aborted.")
def start( self, # type: HummingbotApplication log_level: Optional[str] = None): if threading.current_thread() != threading.main_thread(): self.ev_loop.call_soon_threadsafe(self.start, log_level) return is_valid = self.status() if not is_valid: return strategy_file_path = in_memory_config_map.get( "strategy_file_path").value init_logging( "hummingbot_logs.yml", override_log_level=log_level.upper() if log_level else None, strategy_file_path=strategy_file_path) # If macOS, disable App Nap. if platform.system() == "Darwin": import appnope appnope.nope() # TODO add option to select data feed self.data_feed: DataFeedBase = CoinCapDataFeed.get_instance() self._initialize_notifiers() ExchangeRateConversion.get_instance().start() strategy_name = in_memory_config_map.get("strategy").value self._notify( f"\n Status check complete. Starting '{strategy_name}' strategy..." ) safe_ensure_future(self.start_market_making(strategy_name), loop=self.ev_loop)
async def _import_or_create_strategy_config( self, # type: HummingbotApplication ): """ Special handler function that asks if the user wants to import or create a new strategy config. """ current_strategy: str = in_memory_config_map.get("strategy").value strategy_file_path_cv: ConfigVar = in_memory_config_map.get( "strategy_file_path") choice = await self.app.prompt( prompt="Import previous configs or create a new config file? " "(import/create) >>> ") if choice == "import": strategy_path = await self.app.prompt(strategy_file_path_cv.prompt) strategy_path = strategy_path self._notify( f"Loading previously saved config file from {strategy_path}..." ) elif choice == "create": strategy_path = await copy_strategy_template(current_strategy) self._notify(f"new config file at {strategy_path} created.") else: self._notify('Invalid choice. Please enter "create" or "import".') strategy_path = await self._import_or_create_strategy_config() return strategy_path
async def write_config_to_yml(): """ Write current config saved in config maps into each corresponding yml file """ from hummingbot.client.config.in_memory_config_map import in_memory_config_map current_strategy = in_memory_config_map.get("strategy").value strategy_config_map = get_strategy_config_map(current_strategy) strategy_file_path = join( CONF_FILE_PATH, in_memory_config_map.get("strategy_file_path").value) def save_to_yml(yml_path: str, cm: Dict[str, ConfigVar]): try: with open(yml_path) as stream: data = yaml.load(stream) or {} for key in cm: cvar = cm.get(key) data[key] = cvar.value with open(yml_path, "w+") as outfile: yaml.dump(data, outfile) except Exception as e: logging.getLogger().error("Error writing configs: %s" % (str(e), ), exc_info=True) save_to_yml(GLOBAL_CONFIG_PATH, global_config_map) save_to_yml(strategy_file_path, strategy_config_map)
async def _import_or_create_strategy_config(self): current_strategy: str = in_memory_config_map.get("strategy").value strategy_file_path_cv: ConfigVar = in_memory_config_map.get( "strategy_file_path") choice = await self.app.prompt( prompt="Import previous configs or create a new config file? " "(import/create) >>> ") if choice == "import": strategy_path = await self.app.prompt(strategy_file_path_cv.prompt) strategy_path = strategy_path self.app.log( f"Loading previously saved config file from {strategy_path}..." ) elif choice == "create": strategy_path = await copy_strategy_template(current_strategy) self.app.log(f"new config file at {strategy_path} created.") else: self.app.log('Invalid choice. Please enter "create" or "import".') strategy_path = await self._import_or_create_strategy_config() # Validate response if not strategy_file_path_cv.validate(strategy_path): self.app.log( f"Invalid path {strategy_path}. Please enter \"create\" or \"import\"." ) strategy_path = await self._import_or_create_strategy_config() return strategy_path
def list_trades( self, # type: HummingbotApplication ): if threading.current_thread() != threading.main_thread(): self.ev_loop.call_soon_threadsafe(self.list_trades) return lines = [] # To access the trades from Markets Recorder you need the file path and strategy name if in_memory_config_map.get("strategy_file_path").value is None or \ in_memory_config_map.get("strategy").value is None: self._notify("Bot not started. No past trades.") else: # Query for maximum number of trades to display + 1 queried_trades: List[TradeFill] = self._get_trades_from_session( self.init_time, MAXIMUM_TRADE_FILLS_DISPLAY_OUTPUT + 1) df: pd.DataFrame = TradeFill.to_pandas(queried_trades) if len(df) > 0: # Check if number of trades exceed maximum number of trades to display if len(df) > MAXIMUM_TRADE_FILLS_DISPLAY_OUTPUT: df_lines = str( df[:MAXIMUM_TRADE_FILLS_DISPLAY_OUTPUT]).split("\n") self._notify( f"Number of Trades exceeds the maximum display limit " f"of:{MAXIMUM_TRADE_FILLS_DISPLAY_OUTPUT} trades. " f"Please change limit in client settings to display the required number of trades " ) else: df_lines = str(df).split("\n") lines.extend(["", " Past trades:"] + [" " + line for line in df_lines]) else: lines.extend([" No past trades in this session."]) self._notify("\n".join(lines))
async def _encrypt_n_save_config_value(self, # type: HummingbotApplication cvar: ConfigVar): if in_memory_config_map.get("password").value is None: in_memory_config_map.get("password").value = await self._one_password_config() password = in_memory_config_map.get("password").value if encrypted_config_file_exists(cvar): unlink(get_encrypted_config_path(cvar)) encrypt_n_save_config_value(cvar, password)
def load_required_configs(*args) -> OrderedDict: from hummingbot.client.config.in_memory_config_map import in_memory_config_map current_strategy = in_memory_config_map.get("strategy").value current_strategy_file_path = in_memory_config_map.get("strategy_file_path").value if current_strategy is None or current_strategy_file_path is None: return _merge_dicts(in_memory_config_map) else: strategy_config_map = get_strategy_config_map(current_strategy) # create an ordered dict where `strategy` is inserted first # so that strategy-specific configs are prompted first and populate required exchanges return _merge_dicts(in_memory_config_map, strategy_config_map, global_config_map)
async def write_config_to_yml(): """ Write current config saved in config maps into each corresponding yml file """ from hummingbot.client.config.in_memory_config_map import in_memory_config_map current_strategy = in_memory_config_map.get("strategy").value strategy_config_map = get_strategy_config_map(current_strategy) strategy_file_path = join(CONF_FILE_PATH, in_memory_config_map.get("strategy_file_path").value) await save_to_yml(GLOBAL_CONFIG_PATH, global_config_map) await save_to_yml(strategy_file_path, strategy_config_map)
def _get_config_var_with_key(key: str) -> ConfigVar: current_strategy: str = in_memory_config_map.get("strategy").value strategy_cm: Optional[Dict[str, ConfigVar]] = get_strategy_config_map( current_strategy) if key in in_memory_config_map: cv: ConfigVar = in_memory_config_map.get(key) elif key in global_config_map: cv: ConfigVar = global_config_map.get(key) elif strategy_cm is not None and key in strategy_cm: cv: ConfigVar = strategy_cm.get(key) else: raise ValueError( f"No config variable associated with key name {key}") return cv
async def save_to_yml(yml_path: str, cm: Dict[str, ConfigVar]): """ Write current config saved a single config map into each a single yml file """ try: with open(yml_path) as stream: data = yaml_parser.load(stream) or {} for key in cm: cvar = cm.get(key) if cvar.is_secure: if cvar.value is not None and not encrypted_config_file_exists( cvar): from hummingbot.client.config.in_memory_config_map import in_memory_config_map password = in_memory_config_map.get("password").value encrypt_n_save_config_value(cvar, password) if key in data: data.pop(key) elif type(cvar.value) == Decimal: data[key] = float(cvar.value) else: data[key] = cvar.value with open(yml_path, "w+") as outfile: yaml_parser.dump(data, outfile) except Exception as e: logging.getLogger().error("Error writing configs: %s" % (str(e), ), exc_info=True)
def start( self, # type: HummingbotApplication log_level: Optional[str] = None): is_valid = self.status() if not is_valid: return if log_level is not None: init_logging("hummingbot_logs.yml", override_log_level=log_level.upper()) # If macOS, disable App Nap. if platform.system() == "Darwin": import appnope appnope.nope() # TODO add option to select data feed self.data_feed: DataFeedBase = CoinCapDataFeed.get_instance() self._initialize_notifiers() ExchangeRateConversion.get_instance().start() strategy_name = in_memory_config_map.get("strategy").value self.init_reporting_module() self._notify( f"\n Status check complete. Starting '{strategy_name}' strategy..." ) asyncio.ensure_future(self.start_market_making(strategy_name), loop=self.ev_loop)
def _get_config_var_with_key(key: str) -> ConfigVar: """ Check if key exists in `in_memory_config-map`, `global_config_map`, and `strategy_config_map`. If so, return the corresponding ConfigVar for that key """ current_strategy: str = in_memory_config_map.get("strategy").value strategy_cm: Optional[Dict[str, ConfigVar]] = get_strategy_config_map(current_strategy) if key in in_memory_config_map: cv: ConfigVar = in_memory_config_map.get(key) elif key in global_config_map: cv: ConfigVar = global_config_map.get(key) elif strategy_cm is not None and key in strategy_cm: cv: ConfigVar = strategy_cm.get(key) else: raise ValueError(f"No config variable associated with key name {key}") return cv
def load_secure_var(cvar): if encrypted_config_file_exists(cvar): password = in_memory_config_map.get("password").value if password is not None: cvar.value = decrypt_config_value(cvar, password) return True return False
def list_configs( self, # type: HummingbotApplication ): columns: List[str] = ["Key", "Current Value"] global_cvs: List[ConfigVar] = list( in_memory_config_map.values()) + list(global_config_map.values()) global_data: List[List[Any]] = [[ cv.key, len(str(cv.value)) * "*" if cv.is_secure else str(cv.value) ] for cv in global_cvs] global_df: pd.DataFrame = pd.DataFrame(data=global_data, columns=columns) self._notify("\nglobal configs:") self._notify(str(global_df)) strategy = in_memory_config_map.get("strategy").value if strategy: strategy_cvs: List[ConfigVar] = get_strategy_config_map( strategy).values() strategy_data: List[List[Any]] = [[ cv.key, len(str(cv.value)) * "*" if cv.is_secure else str(cv.value) ] for cv in strategy_cvs] strategy_df: pd.DataFrame = pd.DataFrame(data=strategy_data, columns=columns) self._notify(f"\n{strategy} strategy configs:") self._notify(str(strategy_df)) self._notify("\n")
def read_configs_from_yml(strategy_file_path: str = None): """ Read global config and selected strategy yml files and save the values to corresponding config map """ from hummingbot.client.config.in_memory_config_map import in_memory_config_map current_strategy = in_memory_config_map.get("strategy").value strategy_config_map = get_strategy_config_map(current_strategy) def load_yml_into_cm(yml_path: str, cm: Dict[str, ConfigVar]): try: with open(yml_path) as stream: data = yaml.load(stream) or {} for key in data: if key == "wallet": continue if key in DEPRECATED_CONFIG_VALUES: continue cvar = cm.get(key) val_in_file = data.get(key) if cvar is None: raise ValueError(f"Cannot find corresponding config to key {key}.") cvar.value = val_in_file if val_in_file is not None and not cvar.validate(val_in_file): raise ValueError("Invalid value %s for config variable %s" % (val_in_file, cvar.key)) except Exception as e: logging.getLogger().error("Error loading configs. Your config file may be corrupt. %s" % (e,), exc_info=True) load_yml_into_cm(GLOBAL_CONFIG_PATH, global_config_map) load_yml_into_cm(LIQUIDITY_BOUNTY_CONFIG_PATH, liquidity_bounty_config_map) if strategy_file_path: load_yml_into_cm(join(CONF_FILE_PATH, strategy_file_path), strategy_config_map)
def read_configs_from_yml(strategy_file_path: Optional[str] = None): """ Read global config and selected strategy yml files and save the values to corresponding config map If a yml file is outdated, it gets reformatted with the new template """ from hummingbot.client.config.in_memory_config_map import in_memory_config_map current_strategy = in_memory_config_map.get("strategy").value strategy_config_map: Optional[Dict[str, ConfigVar]] = get_strategy_config_map(current_strategy) def load_yml_into_cm(yml_path: str, template_file_path: str, cm: Dict[str, ConfigVar]): try: with open(yml_path) as stream: data = yaml_parser.load(stream) or {} conf_version = data.get("template_version", 0) with open(template_file_path, "r") as template_fd: template_data = yaml_parser.load(template_fd) template_version = template_data.get("template_version", 0) for key in template_data: if key in {"wallet", "template_version"}: continue cvar = cm.get(key) if cvar is None: logging.getLogger().error(f"Cannot find corresponding config to key {key} in template.") continue # Skip this step since the values are not saved in the yml file if cvar.is_secure: continue val_in_file = data.get(key) if key not in data and cvar.migration_default is not None: cvar.value = cvar.migration_default else: cvar.value = parse_cvar_value(cvar, val_in_file) if val_in_file is not None and not cvar.validate(str(cvar.value)): # Instead of raising an exception, simply skip over this variable and wait till the user is prompted logging.getLogger().error("Invalid value %s for config variable %s" % (val_in_file, cvar.key)) cvar.value = None if conf_version < template_version: # delete old config file if isfile(yml_path): unlink(yml_path) # copy the new file template shutil.copy(template_file_path, yml_path) # save the old variables into the new config file safe_ensure_future(save_to_yml(yml_path, cm)) except Exception as e: logging.getLogger().error("Error loading configs. Your config file may be corrupt. %s" % (e,), exc_info=True) load_yml_into_cm(GLOBAL_CONFIG_PATH, join(TEMPLATE_PATH, "conf_global_TEMPLATE.yml"), global_config_map) if strategy_file_path: strategy_template_path = get_strategy_template_path(current_strategy) load_yml_into_cm(join(CONF_FILE_PATH, strategy_file_path), strategy_template_path, strategy_config_map)
async def _inner_config_loop(self, _keys: List[str], single_key: bool): keys = self.key_filter(_keys) for key in keys: current_strategy: str = in_memory_config_map.get("strategy").value strategy_cm: Dict[str, ConfigVar] = get_strategy_config_map(current_strategy) if key in in_memory_config_map: cv: ConfigVar = in_memory_config_map.get(key) elif key in global_config_map: cv: ConfigVar = global_config_map.get(key) else: cv: ConfigVar = strategy_cm.get(key) value = await self.config_single_variable(cv, is_single_key=single_key) cv.value = parse_cvar_value(cv, value) if single_key: self._notify(f"\nNew config saved:\n{key}: {str(value)}") if not self.config_complete: await self._inner_config_loop(self._get_empty_configs(), single_key)
def get_all_available_config_keys() -> List[str]: all_available_config_keys = list(in_memory_config_map.keys()) + list( global_config_map.keys()) current_strategy: str = in_memory_config_map.get("strategy").value strategy_cm: Optional[Dict[str, ConfigVar]] = get_strategy_config_map( current_strategy) if strategy_cm: all_available_config_keys += list(strategy_cm.keys()) return all_available_config_keys
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()
async def inner_loop(_keys: List[str]): for key in _keys: current_strategy: str = in_memory_config_map.get( "strategy").value strategy_cm: Dict[str, ConfigVar] = get_strategy_config_map( current_strategy) if key in in_memory_config_map: cv: ConfigVar = in_memory_config_map.get(key) elif key in global_config_map: cv: ConfigVar = global_config_map.get(key) else: cv: ConfigVar = strategy_cm.get(key) value = await single_prompt(cv) cv.value = parse_cvar_value(cv, value) if single_key: self.app.log(f"\nNew config saved:\n{key}: {str(value)}") if not self.config_complete: await inner_loop(self._get_empty_configs())
async def list_encrypted( self, # type: HummingbotApplication ): encrypted_files = list_encrypted_file_paths() if len(encrypted_files) == 0: self._notify("There is no encrypted file in your conf folder.") return self.placeholder_mode = True self.app.toggle_hide_input() in_memory_config_map.get( "password").value = await self._one_password_config() password = in_memory_config_map.get("password").value coro = AsyncCallScheduler.shared_instance().call_async( partial(self._list_all_encrypted, encrypted_files, password), timeout_seconds=30) safe_ensure_future(coro) self.app.change_prompt(prompt=">>> ") self.app.toggle_hide_input() self.placeholder_mode = False
def get_all_available_config_keys() -> List[str]: """ Returns a list of config keys that are currently relevant, including the ones that are not required. """ all_available_config_keys = list(in_memory_config_map.keys()) + list(global_config_map.keys()) current_strategy: str = in_memory_config_map.get("strategy").value strategy_cm: Optional[Dict[str, ConfigVar]] = get_strategy_config_map(current_strategy) if strategy_cm: all_available_config_keys += list(strategy_cm.keys()) return all_available_config_keys
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()
async def start_market_making( self, # type: HummingbotApplication strategy_name: str): await ExchangeRateConversion.get_instance().ready_notifier.wait() start_strategy: Callable = get_strategy_starter_file(strategy_name) if strategy_name in STRATEGIES: start_strategy(self) else: raise NotImplementedError try: config_path: str = in_memory_config_map.get( "strategy_file_path").value self.start_time = time.time() * 1e3 # Time in milliseconds self.clock = Clock(ClockMode.REALTIME) if self.wallet is not None: self.clock.add_iterator(self.wallet) for market in self.markets.values(): if market is not None: self.clock.add_iterator(market) self.markets_recorder.restore_market_states( config_path, market) if len(market.limit_orders) > 0: self._notify( f" Cancelling dangling limit orders on {market.name}..." ) await market.cancel_all(5.0) if self.strategy: self.clock.add_iterator(self.strategy) self.strategy_task: asyncio.Task = safe_ensure_future( self._run_clock(), loop=self.ev_loop) self._notify( f"\n '{strategy_name}' strategy started.\n" f" You can use the `status` command to query the progress.") if not self.starting_balances: self.starting_balances = await self.wait_till_ready( self.balance_snapshot) if self._trading_required: self.kill_switch = KillSwitch(self) await self.wait_till_ready(self.kill_switch.start) except Exception as e: self.logger().error(str(e), exc_info=True)
async def main(): await create_yml_files() init_logging("hummingbot_logs.yml") read_configs_from_yml() hb = HummingbotApplication.main_application() hb.acct = unlock_wallet(public_key=WALLET_PUBLIC_KEY, password=WALLET_PASSWORD) with patch_stdout(log_field=hb.app.log_field): init_logging("hummingbot_logs.yml", override_log_level=global_config_map.get("log_level").value) logging.getLogger().info("____DEV_MODE__start_directly__") 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 = STRATEGY_PATH in_memory_config_map.get("strategy_file_path").validate(STRATEGY_PATH) global_config_map.get("wallet").value = WALLET_PUBLIC_KEY tasks: List[Coroutine] = [hb.run()] await asyncio.gather(*tasks)
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_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()
def list(self, obj: str): if obj == "wallets": wallets = list_wallets() if len(wallets) == 0: self.app.log( 'Wallet not available. Please configure your wallet (Enter "config wallet")' ) else: self.app.log('\n'.join(wallets)) elif obj == "exchanges": if len(EXCHANGES) == 0: self.app.log("No exchanges available") else: self.app.log('\n'.join(EXCHANGES)) elif obj == "configs": columns: List[str] = ["Key", "Current Value"] global_cvs: List[ConfigVar] = list( in_memory_config_map.values()) + list( global_config_map.values()) global_data: List[List[str, Any]] = [[ cv.key, len(str(cv.value)) * "*" if cv.is_secure else str(cv.value) ] for cv in global_cvs] global_df: pd.DataFrame = pd.DataFrame(data=global_data, columns=columns) self.app.log("\nglobal configs:") self.app.log(str(global_df)) strategy = in_memory_config_map.get("strategy").value if strategy: strategy_cvs: List[ConfigVar] = get_strategy_config_map( strategy).values() strategy_data: List[List[str, Any]] = [[ cv.key, len(str(cv.value)) * "*" if cv.is_secure else str(cv.value) ] for cv in strategy_cvs] strategy_df: pd.DataFrame = pd.DataFrame(data=strategy_data, columns=columns) self.app.log(f"\n{strategy} strategy configs:") self.app.log(str(strategy_df)) self.app.log("\n") elif obj == "trades": lines = [] if self.strategy is None: self.app.log("No strategy available, cannot show past trades.") else: if len(self.strategy.trades) > 0: df = Trade.to_pandas(self.strategy.trades) df_lines = str(df).split("\n") lines.extend(["", " Past trades:"] + [" " + line for line in df_lines]) else: lines.extend([" No past trades."]) self.app.log("\n".join(lines)) else: self.help("list")
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: self._notify( f"\nPaper trade is enabled for market {market_name}") 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: 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, trading_pairs=trading_pairs, 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, trading_pairs=trading_pairs, 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, trading_pairs=trading_pairs, trading_required=self._trading_required, ) elif market_name == "radar_relay" and self.wallet: 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" 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, 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" and self.wallet: 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 == "bitcoin_com": bitcoin_com_api_key = global_config_map.get( "bitcoin_com_api_key").value bitcoin_com_secret_key = global_config_map.get( "bitcoin_com_secret_key").value market = BitcoinComMarket( bitcoin_com_api_key, bitcoin_com_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()), in_memory_config_map.get("strategy_file_path").value, in_memory_config_map.get("strategy").value, ) self.markets_recorder.start()