def install_packages(path_or_url=None, version=None, authenticator=None): message = "Tentacles installed" success = True if path_or_url and version: path_or_url = _add_version_to_tentacles_package_path( path_or_url, version) for package_url in [path_or_url] if path_or_url else \ tentacles_manager_api.get_registered_tentacle_packages( interfaces_util.get_bot_api().get_edited_tentacles_config()).values(): if not package_url == tentacles_manager_constants.UNKNOWN_TENTACLES_PACKAGE_LOCATION: if not call_tentacle_manager( tentacles_manager_api.install_all_tentacles, package_url, setup_config=interfaces_util.get_bot_api( ).get_edited_tentacles_config(), aiohttp_session=interfaces_util.get_bot_api( ).get_aiohttp_session(), bot_install_dir=octobot_constants.OCTOBOT_FOLDER, authenticator=authenticator): success = False else: message = "Tentacles installed however it is impossible to re-install tentacles with unknown package origin" # reload profiles to display newly installed ones if any interfaces_util.get_edited_config(dict_only=False).load_profiles() if success: return message return False
def remove_profile(profile_id): profile = None if get_current_profile().profile_id == profile_id: return profile, "Can't remove the activated profile" try: profile = interfaces_util.get_edited_config(dict_only=False).profile_by_id[profile_id] interfaces_util.get_edited_config(dict_only=False).remove_profile(profile_id) except errors.ProfileRemovalError as err: return profile, err return profile, None
def start_backtesting_using_specific_files(files, source, reset_tentacle_config=False, run_on_common_part_only=True): try: tools = web_interface_root.WebInterface.tools previous_independent_backtesting = tools[constants.BOT_TOOLS_BACKTESTING] if tools[constants.BOT_TOOLS_STRATEGY_OPTIMIZER] and octobot_api.is_optimizer_in_progress( tools[constants.BOT_TOOLS_STRATEGY_OPTIMIZER]): return False, "Optimizer already running" elif previous_independent_backtesting and \ octobot_api.is_independent_backtesting_in_progress(previous_independent_backtesting): return False, "A backtesting is already running" else: if previous_independent_backtesting: interfaces_util.run_in_bot_main_loop( octobot_api.stop_independent_backtesting(previous_independent_backtesting)) if reset_tentacle_config: tentacles_config = interfaces_util.get_edited_config(dict_only=False).get_tentacles_config_path() tentacles_setup_config = tentacles_manager_api.get_tentacles_setup_config(tentacles_config) else: tentacles_setup_config = interfaces_util.get_bot_api().get_edited_tentacles_config() config = interfaces_util.get_global_config() independent_backtesting = octobot_api.create_independent_backtesting(config, tentacles_setup_config, files, run_on_common_part_only=run_on_common_part_only) interfaces_util.run_in_bot_main_loop( octobot_api.initialize_and_run_independent_backtesting(independent_backtesting), blocking=False) tools[constants.BOT_TOOLS_BACKTESTING] = independent_backtesting tools[constants.BOT_TOOLS_BACKTESTING_SOURCE] = source return True, "Backtesting started" except Exception as e: LOGGER.exception(e, False) return False, f"Error when starting backtesting: {e}"
def duplicate_and_select_profile(profile_id): config = interfaces_util.get_edited_config(dict_only=False) to_duplicate = config.profile_by_id[profile_id] new_profile = config.profile_by_id[profile_id].duplicate(name=f"{to_duplicate.name} (copy)", description=to_duplicate.description) config.load_profiles() _select_and_save(config, new_profile.profile_id)
def update_profile(profile_id, json_profile): config = interfaces_util.get_edited_config(dict_only=False) profile = config.profile_by_id[profile_id] profile.name = json_profile.get("name", profile.name) profile.description = json_profile.get("description", profile.description) profile.avatar = json_profile.get("avatar", profile.avatar) profile.validate_and_save_config()
def is_compatible_account(exchange_name: str, api_key, api_sec, api_pass) -> dict: to_check_config = copy.deepcopy(interfaces_util.get_edited_config()[commons_constants.CONFIG_EXCHANGES].get(exchange_name, {})) if _is_real_exchange_value(api_key): to_check_config[commons_constants.CONFIG_EXCHANGE_KEY] = configuration.encrypt(api_key).decode() if _is_real_exchange_value(api_sec): to_check_config[commons_constants.CONFIG_EXCHANGE_SECRET] = configuration.encrypt(api_sec).decode() if _is_real_exchange_value(api_pass): to_check_config[commons_constants.CONFIG_EXCHANGE_PASSWORD] = configuration.encrypt(api_pass).decode() is_compatible = False is_sponsoring = trading_api.is_sponsoring(exchange_name) is_configured = False authenticator = interfaces_util.get_bot_api().get_community_auth() is_supporter = authenticator.supports.is_supporting() error = None if _is_possible_exchange_config(to_check_config): is_configured = True is_compatible, error = interfaces_util.run_in_bot_async_executor( trading_api.is_compatible_account( exchange_name, to_check_config, interfaces_util.get_edited_tentacles_config() ) ) return { "exchange": exchange_name, "compatible": is_compatible, "supporter_account": is_supporter, "configured": is_configured, "supporting": is_sponsoring, "error_message": error }
def update_global_config(new_config, delete=False): current_edited_config = interfaces_util.get_edited_config(dict_only=False) if not delete: _handle_special_fields(current_edited_config.config, new_config) current_edited_config.update_config_fields(new_config, backtesting_api.is_backtesting_enabled(current_edited_config.config), constants.UPDATED_CONFIG_SEPARATOR, delete=delete) return True
def update_config_currencies(currencies: list, replace: bool=False): """ Update the configured currencies list :param currencies: currencies list :param replace: replace the current list :return: bool, str """ success = True message = "Currencies list updated" try: config_currencies = interfaces_util.get_edited_config()[commons_constants.CONFIG_CRYPTO_CURRENCIES] config_currencies = currencies if replace else \ configuration.merge_dictionaries_by_appending_keys(config_currencies, currencies, merge_sub_array=True) interfaces_util.get_edited_config(dict_only=False).save() except Exception as e: message = f"Error while updating currencies list: {e}" success = False bot_logging.get_logger("ConfigurationWebInterfaceModel").exception(e, False) return success, message
def manage_metrics(enable_metrics): current_edited_config = interfaces_util.get_edited_config(dict_only=False) if commons_constants.CONFIG_METRICS not in current_edited_config.config: current_edited_config.config[commons_constants.CONFIG_METRICS] = { commons_constants.CONFIG_ENABLED_OPTION: enable_metrics} else: current_edited_config.config[commons_constants.CONFIG_METRICS][ commons_constants.CONFIG_ENABLED_OPTION] = enable_metrics if enable_metrics and community.CommunityManager.should_register_bot(current_edited_config): community.CommunityManager.background_get_id_and_register_bot(interfaces_util.get_bot_api()) current_edited_config.save()
def profile(): selected_profile = flask.request.args.get("select", None) if selected_profile is not None and selected_profile != models.get_current_profile( ).profile_id: models.select_profile(selected_profile) current_profile = models.get_current_profile() flask.flash(f"Switched to {current_profile.name} profile.", "success") else: current_profile = models.get_current_profile() media_url = flask.url_for("tentacle_media", _external=True) display_config = interfaces_util.get_edited_config() missing_tentacles = set() profiles = models.get_profiles() config_exchanges = display_config[commons_constants.CONFIG_EXCHANGES] return flask.render_template( 'profile.html', current_profile=current_profile, profiles=profiles, profiles_activated_tentacles=models.get_profiles_activated_tentacles( profiles), config_exchanges=config_exchanges, config_trading=display_config[commons_constants.CONFIG_TRADING], config_trader=display_config[commons_constants.CONFIG_TRADER], config_trader_simulator=display_config[ commons_constants.CONFIG_SIMULATOR], config_symbols=models.format_config_symbols(display_config), config_reference_market=display_config[ commons_constants.CONFIG_TRADING][ commons_constants.CONFIG_TRADER_REFERENCE_MARKET], real_trader_activated=interfaces_util. has_real_and_or_simulated_traders()[0], symbol_list=sorted( models.get_symbol_list([ exchange for exchange in display_config[ commons_constants.CONFIG_EXCHANGES] ])), full_symbol_list=models.get_all_symbols_dict(), evaluator_config=models.get_evaluator_detailed_config( media_url, missing_tentacles), strategy_config=models.get_strategy_config(media_url, missing_tentacles), evaluator_startup_config=models. get_evaluators_tentacles_startup_activation(), trading_startup_config=models.get_trading_tentacles_startup_activation( ), missing_tentacles=missing_tentacles, in_backtesting=backtesting_api.is_backtesting_enabled(display_config), config_tentacles_by_group=models. get_tentacles_activation_desc_by_group(media_url, missing_tentacles), exchanges_details=models.get_exchanges_details(config_exchanges))
def change_reference_market_on_config_currencies(old_base_currency: str, new_base_currency: str) -> bool: """ Change the base currency from old to new for all configured pair :param old_base_currency: :param new_base_currency: :return: bool, str """ success = True message = "Reference market changed for each pair using the old reference market" try: config_currencies = format_config_symbols(interfaces_util.get_edited_config()) regex = rf"/{old_base_currency}$" for currencies_config in config_currencies.values(): currencies_config[commons_constants.CONFIG_CRYPTO_PAIRS] = \ list(set([re.sub(regex, f"/{new_base_currency}", pair) for pair in currencies_config[commons_constants.CONFIG_CRYPTO_PAIRS]])) interfaces_util.get_edited_config(dict_only=False).save() except Exception as e: message = f"Error while changing reference market on currencies list: {e}" success = False bot_logging.get_logger("ConfigurationWebInterfaceModel").exception(e, False) return success, message
def get_watched_symbols(): config = interfaces_util.get_edited_config() if constants.CONFIG_WATCHED_SYMBOLS not in config: config[constants.CONFIG_WATCHED_SYMBOLS] = [] else: try: exchange_manager, _, _ = _get_first_exchange_identifiers() for symbol in copy.copy(config[constants.CONFIG_WATCHED_SYMBOLS]): if not _is_symbol_data_available(exchange_manager, symbol): config[constants.CONFIG_WATCHED_SYMBOLS].remove(symbol) except KeyError: config[constants.CONFIG_WATCHED_SYMBOLS] = [] return config[constants.CONFIG_WATCHED_SYMBOLS]
def update_global_config(new_config, delete=False): current_edited_config = interfaces_util.get_edited_config() if not delete: _handle_special_fields(new_config) config_manager.update_global_config( new_config, current_edited_config, octobot_constants.CONFIG_FILE_SCHEMA, backtesting_api.is_backtesting_enabled(current_edited_config), constants.UPDATED_CONFIG_SEPARATOR, update_input=True, delete=delete) return True
def accounts(): display_config = interfaces_util.get_edited_config() # service lists service_list = models.get_services_list() notifiers_list = models.get_notifiers_list() return flask.render_template('accounts.html', ccxt_tested_exchanges=models.get_tested_exchange_list(), ccxt_simulated_tested_exchanges=models.get_simulated_exchange_list(), ccxt_other_exchanges=sorted(models.get_other_exchange_list()), config_exchanges=display_config[commons_constants.CONFIG_EXCHANGES], config_notifications=display_config[ services_constants.CONFIG_CATEGORY_NOTIFICATION], config_services=display_config[services_constants.CONFIG_CATEGORY_SERVICES], services_list=service_list, notifiers_list=notifiers_list, )
def config(): if flask.request.method == 'POST': request_data = flask.request.get_json() success = True response = "" if request_data: # update trading config if required if constants.TRADING_CONFIG_KEY in request_data and request_data[ constants.TRADING_CONFIG_KEY]: success = success and models.update_tentacles_activation_config( request_data[constants.TRADING_CONFIG_KEY]) else: request_data[constants.TRADING_CONFIG_KEY] = "" # update tentacles config if required if constants.TENTACLES_CONFIG_KEY in request_data and request_data[ constants.TENTACLES_CONFIG_KEY]: success = success and models.update_tentacles_activation_config( request_data[constants.TENTACLES_CONFIG_KEY]) else: request_data[constants.TENTACLES_CONFIG_KEY] = "" # update evaluator config if required if constants.EVALUATOR_CONFIG_KEY in request_data and request_data[ constants.EVALUATOR_CONFIG_KEY]: deactivate_others = False if constants.DEACTIVATE_OTHERS in request_data: deactivate_others = request_data[ constants.DEACTIVATE_OTHERS] success = success and models.update_tentacles_activation_config( request_data[constants.EVALUATOR_CONFIG_KEY], deactivate_others) else: request_data[constants.EVALUATOR_CONFIG_KEY] = "" # remove elements from global config if any to remove removed_elements_key = "removed_elements" if removed_elements_key in request_data and request_data[ removed_elements_key]: success = success and models.update_global_config( request_data[removed_elements_key], delete=True) else: request_data[removed_elements_key] = "" # update global config if required if constants.GLOBAL_CONFIG_KEY in request_data and request_data[ constants.GLOBAL_CONFIG_KEY]: success = models.update_global_config( request_data[constants.GLOBAL_CONFIG_KEY]) else: request_data[constants.GLOBAL_CONFIG_KEY] = "" response = { "evaluator_updated_config": request_data[constants.EVALUATOR_CONFIG_KEY], "trading_updated_config": request_data[constants.TRADING_CONFIG_KEY], "tentacle_updated_config": request_data[constants.TENTACLES_CONFIG_KEY], "global_updated_config": request_data[constants.GLOBAL_CONFIG_KEY], removed_elements_key: request_data[removed_elements_key] } if success: if request_data.get("restart_after_save", False): models.schedule_delayed_command(models.restart_bot) return util.get_rest_reply(flask.jsonify(response)) else: return util.get_rest_reply('{"update": "ko"}', 500) else: media_url = flask.url_for("tentacle_media", _external=True) display_config = interfaces_util.get_edited_config() # service lists service_list = models.get_services_list() notifiers_list = models.get_notifiers_list() return flask.render_template( 'config.html', config_exchanges=display_config[ commons_constants.CONFIG_EXCHANGES], config_trading=display_config[commons_constants.CONFIG_TRADING], config_trader=display_config[commons_constants.CONFIG_TRADER], config_trader_simulator=display_config[ commons_constants.CONFIG_SIMULATOR], config_notifications=display_config[ services_constants.CONFIG_CATEGORY_NOTIFICATION], config_services=display_config[ services_constants.CONFIG_CATEGORY_SERVICES], config_symbols=models.format_config_symbols(display_config), config_reference_market=display_config[ commons_constants.CONFIG_TRADING][ commons_constants.CONFIG_TRADER_REFERENCE_MARKET], real_trader_activated=interfaces_util. has_real_and_or_simulated_traders()[0], ccxt_tested_exchanges=models.get_tested_exchange_list(), ccxt_simulated_tested_exchanges=models.get_simulated_exchange_list( ), ccxt_other_exchanges=sorted(models.get_other_exchange_list()), services_list=service_list, notifiers_list=notifiers_list, symbol_list=sorted( models.get_symbol_list([ exchange for exchange in display_config[ commons_constants.CONFIG_EXCHANGES] ])), full_symbol_list=models.get_all_symbols_dict(), strategy_config=models.get_strategy_config(media_url), evaluator_startup_config=models. get_evaluators_tentacles_startup_activation(), trading_startup_config=models. get_trading_tentacles_startup_activation(), in_backtesting=backtesting_api.is_backtesting_enabled( display_config), config_tentacles_by_group=models. get_tentacles_activation_desc_by_group(media_url))
def get_profiles(): return interfaces_util.get_edited_config(dict_only=False).profile_by_id
def select_profile(profile_id): config = interfaces_util.get_edited_config(dict_only=False) _select_and_save(config, profile_id)
def get_current_profile(): return interfaces_util.get_edited_config(dict_only=False).profile
def import_profile(profile_path, name): profiles.import_profile(profile_path, name=name) interfaces_util.get_edited_config(dict_only=False).load_profiles()
def _save_edition(): interfaces_util.get_edited_config(dict_only=False).save( schema_file=octobot_contants.CONFIG_FILE_SCHEMA) return True
def get_profile_name(profile_id) -> str: return interfaces_util.get_edited_config( dict_only=False).profile_by_id[profile_id].name
def get_metrics_enabled(): return config_manager.get_metrics_enabled( interfaces_util.get_edited_config())
def _save_edition(): config_manager.simple_save_config_update(interfaces_util.get_edited_config(), schema_file=octobot_contants.CONFIG_FILE_SCHEMA) return True
def export_profile(profile_id, export_path) -> str: return profiles.export_profile( interfaces_util.get_edited_config( dict_only=False).profile_by_id[profile_id], export_path)
def accept_terms(accepted): return config_manager.accept_terms(interfaces_util.get_edited_config(), accepted)
def can_get_community_metrics(): return octobot_community.can_read_metrics( interfaces_util.get_edited_config(dict_only=False))
def get_config_currency(): return flask.jsonify( models.format_config_symbols(interfaces_util.get_edited_config()))
def accept_terms(accepted): return interfaces_util.get_edited_config( dict_only=False).accept_terms(accepted)
def get_watched_symbols(): config = interfaces_util.get_edited_config() if constants.CONFIG_WATCHED_SYMBOLS not in config: config[constants.CONFIG_WATCHED_SYMBOLS] = [] return config[constants.CONFIG_WATCHED_SYMBOLS]
def get_metrics_enabled(): return interfaces_util.get_edited_config( dict_only=False).get_metrics_enabled()