def profiles_management(action): if action == "update": data = flask.request.get_json() models.update_profile(flask.request.get_json()["id"], data) return util.get_rest_reply(flask.jsonify(data)) if action == "duplicate": profile_id = flask.request.args.get("profile_id") models.duplicate_and_select_profile(profile_id) flask.flash(f"New profile successfully created and selected.", "success") return util.get_rest_reply(flask.jsonify("Profile created")) if action == "remove": data = flask.request.get_json() to_remove_id = data["id"] removed_profile, err = models.remove_profile(to_remove_id) if err is not None: return util.get_rest_reply(flask.jsonify(str(err)), code=400) flask.flash(f"{removed_profile.name} profile removed.", "success") return util.get_rest_reply(flask.jsonify("Profile created")) if action == "import": file = flask.request.files['file'] name = werkzeug.utils.secure_filename( flask.request.files['file'].filename) models.import_profile(file, name) flask.flash(f"{name} profile successfully imported.", "success") return flask.redirect(flask.url_for('profile')) if action == "export": profile_id = flask.request.args.get("profile_id") temp_file = os.path.abspath("profile") file_path = models.export_profile(profile_id, temp_file) name = models.get_profile_name(profile_id) return flask_util.send_and_remove_file( file_path, f"{name}_{datetime.now().strftime('%Y%m%d-%H%M%S')}.zip")
def evaluator_config(): if flask.request.method == 'POST': request_data = flask.request.get_json() success = True response = "" if request_data: # update evaluator config if required if constants.EVALUATOR_CONFIG_KEY in request_data and request_data[ constants.EVALUATOR_CONFIG_KEY]: success = success and models.update_tentacles_activation_config( request_data[constants.EVALUATOR_CONFIG_KEY]) response = { "evaluator_updated_config": request_data[constants.EVALUATOR_CONFIG_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) return flask.render_template( 'advanced_evaluator_config.html', evaluator_config=models.get_evaluator_detailed_config(media_url), evaluator_startup_config=models. get_evaluators_tentacles_startup_activation())
def backtesting(): if flask.request.method == 'POST': action_type = flask.request.args["action_type"] success = False reply = "Action failed" if action_type == "start_backtesting": files = flask.request.get_json() source = flask.request.args["source"] run_on_common_part_only = flask.request.args.get("run_on_common_part_only", "true") == "true" reset_tentacle_config = flask.request.args.get("reset_tentacle_config", False) success, reply = models.start_backtesting_using_specific_files(files, source, reset_tentacle_config, run_on_common_part_only) if success: web_interface.send_backtesting_status() return util.get_rest_reply(flask.jsonify(reply)) else: return util.get_rest_reply(reply, 500) elif flask.request.method == 'GET': if flask.request.args: target = flask.request.args["update_type"] if target == "backtesting_report": source = flask.request.args["source"] backtesting_report = models.get_backtesting_report(source) return flask.jsonify(backtesting_report) else: return flask.render_template('backtesting.html', activated_trading_mode=models.get_config_activated_trading_mode(), data_files=models.get_data_files_with_description())
def set_config_currency(): request_data = flask.request.get_json() success, reply = models.update_config_currencies( request_data["currencies"], replace=(request_data.get("action", "update") == "replace")) return util.get_rest_reply( flask.jsonify(reply)) if success else util.get_rest_reply(reply, 500)
def _handle_package_operation(update_type): if update_type == "add_package": request_data = flask.request.get_json() success = False if request_data: path_or_url, action = next(iter(request_data.items())) path_or_url = path_or_url.strip() if action == "register_and_install": installation_result = models.install_packages(path_or_url) if installation_result: return util.get_rest_reply(flask.jsonify(installation_result)) else: return util.get_rest_reply('Impossible to install the given tentacles package, #TODO in 0.4.', 500) if not success: return util.get_rest_reply('{"operation": "ko"}', 500) elif update_type in ["install_packages", "update_packages", "reset_packages"]: packages_operation_result = {} if update_type == "install_packages": packages_operation_result = models.install_packages() elif update_type == "update_packages": packages_operation_result = models.update_packages() elif update_type == "reset_packages": packages_operation_result = models.reset_packages() if packages_operation_result is not None: return util.get_rest_reply(flask.jsonify(packages_operation_result)) else: action = update_type.split("_")[0] return util.get_rest_reply(f'Impossible to {action} packages, check the logs for more information.', 500)
def config(): 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)
def strategy_optimizer(): if flask.request.method == 'POST': update_type = flask.request.args["update_type"] request_data = flask.request.get_json() success = False reply = "Operation OK" if request_data: if update_type == "start_optimizer": try: strategy = request_data["strategy"][0] time_frames = request_data["time_frames"] evaluators = request_data["evaluators"] risks = request_data["risks"] success, reply = models.start_optimizer( strategy, time_frames, evaluators, risks) except Exception as e: return util.get_rest_reply( '{"start_optimizer": "ko: ' + str(e) + '"}', 500) if success: return util.get_rest_reply(flask.jsonify(reply)) else: return util.get_rest_reply(reply, 500) elif flask.request.method == 'GET': if flask.request.args: target = flask.request.args["update_type"] if target == "optimizer_results": optimizer_results = models.get_optimizer_results() return flask.jsonify(optimizer_results) if target == "optimizer_report": optimizer_report = models.get_optimizer_report() return flask.jsonify(optimizer_report) if target == "strategy_params": strategy_name = flask.request.args["strategy_name"] params = { "time_frames": list(models.get_time_frames_list(strategy_name)), "evaluators": list(models.get_evaluators_list(strategy_name)) } return flask.jsonify(params) else: trading_mode = models.get_config_activated_trading_mode() strategies = models.get_strategies_list(trading_mode) current_strategy = strategies[0] if strategies else "" return flask.render_template( 'advanced_strategy_optimizer.html', strategies=strategies, current_strategy=current_strategy, time_frames=models.get_time_frames_list(current_strategy), evaluators=models.get_evaluators_list(current_strategy), risks=models.get_risks_list(), trading_mode=trading_mode.get_name(), run_params=models.get_current_run_params())
def data_collector(): if flask.request.method == 'POST': action_type = flask.request.args["action_type"] success = False reply = "Action failed" if action_type == "delete_data_file": file = flask.request.get_json() success, reply = models.get_delete_data_file(file) elif action_type == "start_collector": details = flask.request.get_json() success, reply = models.collect_data_file(details["exchange"], details["symbol"]) elif action_type == "import_data_file": if flask.request.files: file = flask.request.files['file'] name = werkzeug.utils.secure_filename(flask.request.files['file'].filename) success, reply = models.save_data_file(name, file) alert = {"success": success, "message": reply} else: alert = {} current_exchange = models.get_current_exchange() # here return template to force page reload because of file upload via input form return flask.render_template('data_collector.html', data_files=models.get_data_files_with_description(), ccxt_exchanges=sorted(models.get_full_exchange_list()), current_exchange=models.get_current_exchange(), full_symbol_list=sorted(models.get_symbol_list([current_exchange])), alert=alert) if success: return util.get_rest_reply(flask.jsonify(reply)) else: return util.get_rest_reply(reply, 500) elif flask.request.method == 'GET': origin_page = None if flask.request.args: action_type_key = "action_type" if action_type_key in flask.request.args: target = flask.request.args[action_type_key] if target == "symbol_list": exchange = flask.request.args.get('exchange') return flask.jsonify(sorted(models.get_symbol_list([exchange]))) from_key = "from" if from_key in flask.request.args: origin_page = flask.request.args[from_key] current_exchange = models.get_current_exchange() return flask.render_template('data_collector.html', data_files=models.get_data_files_with_description(), ccxt_exchanges=sorted(models.get_full_exchange_list()), current_exchange=models.get_current_exchange(), full_symbol_list=sorted(models.get_symbol_list([current_exchange])), origin_page=origin_page, alert={})
def config_tentacle(): if flask.request.method == 'POST': tentacle_name = flask.request.args.get("name") action = flask.request.args.get("action") success = True response = "" if action == "update": request_data = flask.request.get_json() success, response = models.update_tentacle_config( tentacle_name, request_data) elif action == "factory_reset": success, response = models.reset_config_to_default(tentacle_name) if success: return util.get_rest_reply(flask.jsonify(response)) else: return util.get_rest_reply(response, 500) else: if flask.request.args: tentacle_name = flask.request.args.get("name") missing_tentacles = set() media_url = flask.url_for("tentacle_media", _external=True) tentacle_class, tentacle_type, tentacle_desc = models.get_tentacle_from_string( tentacle_name, media_url) evaluator_config = models.get_evaluator_detailed_config(media_url, missing_tentacles) if tentacle_type == "strategy" and \ tentacle_desc[ models.REQUIREMENTS_KEY] == [ "*"] else None strategy_config = models.get_strategy_config(media_url, missing_tentacles) if tentacle_type == "trading mode" and \ len(tentacle_desc[ models.REQUIREMENTS_KEY]) > 1 else None evaluator_startup_config = models.get_evaluators_tentacles_startup_activation() \ if evaluator_config or strategy_config else None tentacle_commands = models.get_tentacle_user_commands( tentacle_class) return flask.render_template( 'config_tentacle.html', name=tentacle_name, tentacle_type=tentacle_type, tentacle_class=tentacle_class, tentacle_desc=tentacle_desc, evaluator_startup_config=evaluator_startup_config, strategy_config=strategy_config, evaluator_config=evaluator_config, activated_trading_mode=models. get_config_activated_trading_mode(), data_files=models.get_data_files_with_description(), missing_tentacles=missing_tentacles, user_commands=tentacle_commands, current_profile=models.get_current_profile()) else: return flask.render_template('config_tentacle.html')
def _handle_module_operation(update_type): request_data = flask.request.get_json() if request_data: packages_operation_result = {} if update_type == "update_modules": packages_operation_result = models.update_modules(request_data) elif update_type == "uninstall_modules": packages_operation_result = models.uninstall_modules(request_data) if packages_operation_result is not None: return util.get_rest_reply(flask.jsonify(packages_operation_result)) else: action = update_type.split("_")[0] return util.get_rest_reply(f'Impossible to {action} module(s), check the logs for more information.', 500) else: return util.get_rest_reply('{"Need at least one element be selected": "ko"}', 500)
def internal_error(error): bot_logging.get_logger("WebInterfaceErrorHandler").exception(error.original_exception, True, f"Error when displaying page: " f"{error.original_exception}") if flask.request.content_type == APP_JSON_CONTENT_TYPE: return util.get_rest_reply("We are sorry, but an unexpected error occurred", 500) return flask.render_template("500.html")
def watched_symbols(): if flask.request.method == 'POST': result = False request_data = flask.request.get_json() symbol = request_data["symbol"] action = request_data["action"] action_desc = "added to" if action == 'add': result = models.add_watched_symbol(symbol) elif action == 'remove': result = models.remove_watched_symbol(symbol) action_desc = "removed from" if result: return util.get_rest_reply( flask.jsonify(f"{symbol} {action_desc} watched markets")) else: return util.get_rest_reply( f'Error: {symbol} not {action_desc} watched markets.', 500)
def profiles_management(action): if action == "update": data = flask.request.get_json() models.update_profile(flask.request.get_json()["id"], data) return util.get_rest_reply(flask.jsonify(data)) if action == "duplicate": profile_id = flask.request.args.get("profile_id") models.duplicate_and_select_profile(profile_id) flask.flash(f"New profile successfully created and selected.", "success") return util.get_rest_reply(flask.jsonify("Profile created")) if action == "remove": data = flask.request.get_json() to_remove_id = data["id"] removed_profile, err = models.remove_profile(to_remove_id) if err is not None: return util.get_rest_reply(flask.jsonify(str(err)), code=400) flask.flash(f"{removed_profile.name} profile removed.", "success") return util.get_rest_reply(flask.jsonify("Profile created")) if action == "import": file = flask.request.files['file'] name = werkzeug.utils.secure_filename(flask.request.files['file'].filename) models.import_profile(file, name) flask.flash(f"{name} profile successfully imported.", "success") return flask.redirect(flask.url_for('profile')) if action == "export": profile_id = flask.request.args.get("profile_id") temp_file = os.path.abspath("profile") file_path = models.export_profile(profile_id, temp_file) try: return flask.send_file(file_path, as_attachment=True, attachment_filename="profile.zip", cache_timeout=0) finally: # cleanup temp_file def remove_file(file_path): try: os.remove(file_path) except Exception: pass models.schedule_delayed_command(remove_file, file_path, delay=2)
def orders(): if flask.request.method == 'GET': real_open_orders, simulated_open_orders = interfaces_util.get_all_open_orders( ) return json.dumps({ "real_open_orders": real_open_orders, "simulated_open_orders": simulated_open_orders }) elif flask.request.method == "POST": result = "" request_data = flask.request.get_json() action = flask.request.args.get("action") if action == "cancel_order": if interfaces_util.cancel_orders([request_data]): result = "Order cancelled" else: return util.get_rest_reply( 'Impossible to cancel order: order not found.', 500) elif action == "cancel_orders": removed_count = interfaces_util.cancel_orders(request_data) result = f"{removed_count} orders cancelled" return flask.jsonify(result)
def change_reference_market_on_config_currencies(): request_data = flask.request.get_json() success, reply = models.change_reference_market_on_config_currencies( request_data["old_base_currency"], request_data["new_base_currency"]) return util.get_rest_reply( flask.jsonify(reply)) if success else util.get_rest_reply(reply, 500)
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 not_found(_): if flask.request.content_type == APP_JSON_CONTENT_TYPE: return util.get_rest_reply("We are sorry, but this doesn't exist", 404) return flask.render_template("404.html"), 404
def refresh_portfolio(): try: interfaces_util.trigger_portfolios_refresh() return flask.jsonify("Portfolio(s) refreshed") except RuntimeError: return util.get_rest_reply("No portfolio to refresh", 500)
def metrics_settings(): enable_metrics = flask.request.get_json() return util.get_rest_reply(flask.jsonify(models.manage_metrics(enable_metrics)))
def config_actions(): # action = flask.request.args.get("action") return util.get_rest_reply("No specified action.", code=500)