예제 #1
0
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")
예제 #2
0
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())
예제 #3
0
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())
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
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())
예제 #8
0
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={})
예제 #9
0
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')
예제 #10
0
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)
예제 #11
0
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")
예제 #12
0
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)
예제 #13
0
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)
예제 #14
0
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)
예제 #15
0
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)
예제 #16
0
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))
예제 #17
0
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
예제 #18
0
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)
예제 #19
0
def metrics_settings():
    enable_metrics = flask.request.get_json()
    return util.get_rest_reply(flask.jsonify(models.manage_metrics(enable_metrics)))
예제 #20
0
def config_actions():
    # action = flask.request.args.get("action")
    return util.get_rest_reply("No specified action.", code=500)