mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 10:21:59 +00:00
ruff format: commands
This commit is contained in:
parent
5eb4ad2208
commit
3c9be47236
|
@ -6,6 +6,7 @@ Contains all start-commands, subcommands and CLI Interface creation.
|
||||||
Note: Be careful with file-scoped imports in these subfiles.
|
Note: Be careful with file-scoped imports in these subfiles.
|
||||||
as they are parsed on startup, nothing containing optional modules should be loaded.
|
as they are parsed on startup, nothing containing optional modules should be loaded.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from freqtrade.commands.analyze_commands import start_analysis_entries_exits
|
from freqtrade.commands.analyze_commands import start_analysis_entries_exits
|
||||||
from freqtrade.commands.arguments import Arguments
|
from freqtrade.commands.arguments import Arguments
|
||||||
from freqtrade.commands.build_config_commands import start_new_config, start_show_config
|
from freqtrade.commands.build_config_commands import start_new_config, start_show_config
|
||||||
|
|
|
@ -20,25 +20,25 @@ def setup_analyze_configuration(args: Dict[str, Any], method: RunMode) -> Dict[s
|
||||||
config = setup_utils_configuration(args, method)
|
config = setup_utils_configuration(args, method)
|
||||||
|
|
||||||
no_unlimited_runmodes = {
|
no_unlimited_runmodes = {
|
||||||
RunMode.BACKTEST: 'backtesting',
|
RunMode.BACKTEST: "backtesting",
|
||||||
}
|
}
|
||||||
if method in no_unlimited_runmodes.keys():
|
if method in no_unlimited_runmodes.keys():
|
||||||
from freqtrade.data.btanalysis import get_latest_backtest_filename
|
from freqtrade.data.btanalysis import get_latest_backtest_filename
|
||||||
|
|
||||||
if 'exportfilename' in config:
|
if "exportfilename" in config:
|
||||||
if config['exportfilename'].is_dir():
|
if config["exportfilename"].is_dir():
|
||||||
btfile = Path(get_latest_backtest_filename(config['exportfilename']))
|
btfile = Path(get_latest_backtest_filename(config["exportfilename"]))
|
||||||
signals_file = f"{config['exportfilename']}/{btfile.stem}_signals.pkl"
|
signals_file = f"{config['exportfilename']}/{btfile.stem}_signals.pkl"
|
||||||
else:
|
else:
|
||||||
if config['exportfilename'].exists():
|
if config["exportfilename"].exists():
|
||||||
btfile = Path(config['exportfilename'])
|
btfile = Path(config["exportfilename"])
|
||||||
signals_file = f"{btfile.parent}/{btfile.stem}_signals.pkl"
|
signals_file = f"{btfile.parent}/{btfile.stem}_signals.pkl"
|
||||||
else:
|
else:
|
||||||
raise ConfigurationError(f"{config['exportfilename']} does not exist.")
|
raise ConfigurationError(f"{config['exportfilename']} does not exist.")
|
||||||
else:
|
else:
|
||||||
raise ConfigurationError('exportfilename not in config.')
|
raise ConfigurationError("exportfilename not in config.")
|
||||||
|
|
||||||
if (not Path(signals_file).exists()):
|
if not Path(signals_file).exists():
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f"Cannot find latest backtest signals file: {signals_file}."
|
f"Cannot find latest backtest signals file: {signals_file}."
|
||||||
"Run backtesting with `--export signals`."
|
"Run backtesting with `--export signals`."
|
||||||
|
@ -58,6 +58,6 @@ def start_analysis_entries_exits(args: Dict[str, Any]) -> None:
|
||||||
# Initialize configuration
|
# Initialize configuration
|
||||||
config = setup_analyze_configuration(args, RunMode.BACKTEST)
|
config = setup_analyze_configuration(args, RunMode.BACKTEST)
|
||||||
|
|
||||||
logger.info('Starting freqtrade in analysis mode')
|
logger.info("Starting freqtrade in analysis mode")
|
||||||
|
|
||||||
process_entry_exit_reasons(config)
|
process_entry_exit_reasons(config)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
This module contains the argument manager class
|
This module contains the argument manager class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
@ -12,35 +13,72 @@ from freqtrade.constants import DEFAULT_CONFIG
|
||||||
|
|
||||||
ARGS_COMMON = ["verbosity", "logfile", "version", "config", "datadir", "user_data_dir"]
|
ARGS_COMMON = ["verbosity", "logfile", "version", "config", "datadir", "user_data_dir"]
|
||||||
|
|
||||||
ARGS_STRATEGY = ["strategy", "strategy_path", "recursive_strategy_search", "freqaimodel",
|
ARGS_STRATEGY = [
|
||||||
"freqaimodel_path"]
|
"strategy",
|
||||||
|
"strategy_path",
|
||||||
|
"recursive_strategy_search",
|
||||||
|
"freqaimodel",
|
||||||
|
"freqaimodel_path",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_TRADE = ["db_url", "sd_notify", "dry_run", "dry_run_wallet", "fee"]
|
ARGS_TRADE = ["db_url", "sd_notify", "dry_run", "dry_run_wallet", "fee"]
|
||||||
|
|
||||||
ARGS_WEBSERVER: List[str] = []
|
ARGS_WEBSERVER: List[str] = []
|
||||||
|
|
||||||
ARGS_COMMON_OPTIMIZE = ["timeframe", "timerange", "dataformat_ohlcv",
|
ARGS_COMMON_OPTIMIZE = [
|
||||||
"max_open_trades", "stake_amount", "fee", "pairs"]
|
"timeframe",
|
||||||
|
"timerange",
|
||||||
|
"dataformat_ohlcv",
|
||||||
|
"max_open_trades",
|
||||||
|
"stake_amount",
|
||||||
|
"fee",
|
||||||
|
"pairs",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions",
|
ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + [
|
||||||
"enable_protections", "dry_run_wallet", "timeframe_detail",
|
"position_stacking",
|
||||||
"strategy_list", "export", "exportfilename",
|
"use_max_market_positions",
|
||||||
"backtest_breakdown", "backtest_cache",
|
"enable_protections",
|
||||||
"freqai_backtest_live_models"]
|
"dry_run_wallet",
|
||||||
|
"timeframe_detail",
|
||||||
|
"strategy_list",
|
||||||
|
"export",
|
||||||
|
"exportfilename",
|
||||||
|
"backtest_breakdown",
|
||||||
|
"backtest_cache",
|
||||||
|
"freqai_backtest_live_models",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path",
|
ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + [
|
||||||
"position_stacking", "use_max_market_positions",
|
"hyperopt",
|
||||||
"enable_protections", "dry_run_wallet", "timeframe_detail",
|
"hyperopt_path",
|
||||||
"epochs", "spaces", "print_all",
|
"position_stacking",
|
||||||
"print_colorized", "print_json", "hyperopt_jobs",
|
"use_max_market_positions",
|
||||||
"hyperopt_random_state", "hyperopt_min_trades",
|
"enable_protections",
|
||||||
"hyperopt_loss", "disableparamexport",
|
"dry_run_wallet",
|
||||||
"hyperopt_ignore_missing_space", "analyze_per_epoch"]
|
"timeframe_detail",
|
||||||
|
"epochs",
|
||||||
|
"spaces",
|
||||||
|
"print_all",
|
||||||
|
"print_colorized",
|
||||||
|
"print_json",
|
||||||
|
"hyperopt_jobs",
|
||||||
|
"hyperopt_random_state",
|
||||||
|
"hyperopt_min_trades",
|
||||||
|
"hyperopt_loss",
|
||||||
|
"disableparamexport",
|
||||||
|
"hyperopt_ignore_missing_space",
|
||||||
|
"analyze_per_epoch",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"]
|
ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"]
|
||||||
|
|
||||||
ARGS_LIST_STRATEGIES = ["strategy_path", "print_one_column", "print_colorized",
|
ARGS_LIST_STRATEGIES = [
|
||||||
"recursive_strategy_search"]
|
"strategy_path",
|
||||||
|
"print_one_column",
|
||||||
|
"print_colorized",
|
||||||
|
"recursive_strategy_search",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_LIST_FREQAIMODELS = ["freqaimodel_path", "print_one_column", "print_colorized"]
|
ARGS_LIST_FREQAIMODELS = ["freqaimodel_path", "print_one_column", "print_colorized"]
|
||||||
|
|
||||||
|
@ -52,12 +90,27 @@ ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all"]
|
||||||
|
|
||||||
ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"]
|
ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"]
|
||||||
|
|
||||||
ARGS_LIST_PAIRS = ["exchange", "print_list", "list_pairs_print_json", "print_one_column",
|
ARGS_LIST_PAIRS = [
|
||||||
"print_csv", "base_currencies", "quote_currencies", "list_pairs_all",
|
"exchange",
|
||||||
"trading_mode"]
|
"print_list",
|
||||||
|
"list_pairs_print_json",
|
||||||
|
"print_one_column",
|
||||||
|
"print_csv",
|
||||||
|
"base_currencies",
|
||||||
|
"quote_currencies",
|
||||||
|
"list_pairs_all",
|
||||||
|
"trading_mode",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_TEST_PAIRLIST = ["user_data_dir", "verbosity", "config", "quote_currencies",
|
ARGS_TEST_PAIRLIST = [
|
||||||
"print_one_column", "list_pairs_print_json", "exchange"]
|
"user_data_dir",
|
||||||
|
"verbosity",
|
||||||
|
"config",
|
||||||
|
"quote_currencies",
|
||||||
|
"print_one_column",
|
||||||
|
"list_pairs_print_json",
|
||||||
|
"exchange",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_CREATE_USERDIR = ["user_data_dir", "reset"]
|
ARGS_CREATE_USERDIR = ["user_data_dir", "reset"]
|
||||||
|
|
||||||
|
@ -70,22 +123,58 @@ ARGS_CONVERT_DATA_TRADES = ["pairs", "format_from_trades", "format_to", "erase",
|
||||||
ARGS_CONVERT_DATA = ["pairs", "format_from", "format_to", "erase", "exchange"]
|
ARGS_CONVERT_DATA = ["pairs", "format_from", "format_to", "erase", "exchange"]
|
||||||
ARGS_CONVERT_DATA_OHLCV = ARGS_CONVERT_DATA + ["timeframes", "trading_mode", "candle_types"]
|
ARGS_CONVERT_DATA_OHLCV = ARGS_CONVERT_DATA + ["timeframes", "trading_mode", "candle_types"]
|
||||||
|
|
||||||
ARGS_CONVERT_TRADES = ["pairs", "timeframes", "exchange", "dataformat_ohlcv", "dataformat_trades",
|
ARGS_CONVERT_TRADES = [
|
||||||
"trading_mode"]
|
"pairs",
|
||||||
|
"timeframes",
|
||||||
|
"exchange",
|
||||||
|
"dataformat_ohlcv",
|
||||||
|
"dataformat_trades",
|
||||||
|
"trading_mode",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_LIST_DATA = ["exchange", "dataformat_ohlcv", "pairs", "trading_mode", "show_timerange"]
|
ARGS_LIST_DATA = ["exchange", "dataformat_ohlcv", "pairs", "trading_mode", "show_timerange"]
|
||||||
|
|
||||||
ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "new_pairs_days", "include_inactive",
|
ARGS_DOWNLOAD_DATA = [
|
||||||
"timerange", "download_trades", "exchange", "timeframes",
|
"pairs",
|
||||||
"erase", "dataformat_ohlcv", "dataformat_trades", "trading_mode",
|
"pairs_file",
|
||||||
"prepend_data"]
|
"days",
|
||||||
|
"new_pairs_days",
|
||||||
|
"include_inactive",
|
||||||
|
"timerange",
|
||||||
|
"download_trades",
|
||||||
|
"exchange",
|
||||||
|
"timeframes",
|
||||||
|
"erase",
|
||||||
|
"dataformat_ohlcv",
|
||||||
|
"dataformat_trades",
|
||||||
|
"trading_mode",
|
||||||
|
"prepend_data",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit",
|
ARGS_PLOT_DATAFRAME = [
|
||||||
"db_url", "trade_source", "export", "exportfilename",
|
"pairs",
|
||||||
"timerange", "timeframe", "no_trades"]
|
"indicators1",
|
||||||
|
"indicators2",
|
||||||
|
"plot_limit",
|
||||||
|
"db_url",
|
||||||
|
"trade_source",
|
||||||
|
"export",
|
||||||
|
"exportfilename",
|
||||||
|
"timerange",
|
||||||
|
"timeframe",
|
||||||
|
"no_trades",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url",
|
ARGS_PLOT_PROFIT = [
|
||||||
"trade_source", "timeframe", "plot_auto_open", ]
|
"pairs",
|
||||||
|
"timerange",
|
||||||
|
"export",
|
||||||
|
"exportfilename",
|
||||||
|
"db_url",
|
||||||
|
"trade_source",
|
||||||
|
"timeframe",
|
||||||
|
"plot_auto_open",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_CONVERT_DB = ["db_url", "db_url_from"]
|
ARGS_CONVERT_DB = ["db_url", "db_url_from"]
|
||||||
|
|
||||||
|
@ -93,36 +182,76 @@ ARGS_INSTALL_UI = ["erase_ui_only", "ui_version"]
|
||||||
|
|
||||||
ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"]
|
ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"]
|
||||||
|
|
||||||
ARGS_HYPEROPT_LIST = ["hyperopt_list_best", "hyperopt_list_profitable",
|
ARGS_HYPEROPT_LIST = [
|
||||||
"hyperopt_list_min_trades", "hyperopt_list_max_trades",
|
"hyperopt_list_best",
|
||||||
"hyperopt_list_min_avg_time", "hyperopt_list_max_avg_time",
|
"hyperopt_list_profitable",
|
||||||
"hyperopt_list_min_avg_profit", "hyperopt_list_max_avg_profit",
|
"hyperopt_list_min_trades",
|
||||||
"hyperopt_list_min_total_profit", "hyperopt_list_max_total_profit",
|
"hyperopt_list_max_trades",
|
||||||
"hyperopt_list_min_objective", "hyperopt_list_max_objective",
|
"hyperopt_list_min_avg_time",
|
||||||
"print_colorized", "print_json", "hyperopt_list_no_details",
|
"hyperopt_list_max_avg_time",
|
||||||
"hyperoptexportfilename", "export_csv"]
|
"hyperopt_list_min_avg_profit",
|
||||||
|
"hyperopt_list_max_avg_profit",
|
||||||
|
"hyperopt_list_min_total_profit",
|
||||||
|
"hyperopt_list_max_total_profit",
|
||||||
|
"hyperopt_list_min_objective",
|
||||||
|
"hyperopt_list_max_objective",
|
||||||
|
"print_colorized",
|
||||||
|
"print_json",
|
||||||
|
"hyperopt_list_no_details",
|
||||||
|
"hyperoptexportfilename",
|
||||||
|
"export_csv",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_show_index",
|
ARGS_HYPEROPT_SHOW = [
|
||||||
"print_json", "hyperoptexportfilename", "hyperopt_show_no_header",
|
"hyperopt_list_best",
|
||||||
"disableparamexport", "backtest_breakdown"]
|
"hyperopt_list_profitable",
|
||||||
|
"hyperopt_show_index",
|
||||||
|
"print_json",
|
||||||
|
"hyperoptexportfilename",
|
||||||
|
"hyperopt_show_no_header",
|
||||||
|
"disableparamexport",
|
||||||
|
"backtest_breakdown",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_ANALYZE_ENTRIES_EXITS = ["exportfilename", "analysis_groups", "enter_reason_list",
|
ARGS_ANALYZE_ENTRIES_EXITS = [
|
||||||
"exit_reason_list", "indicator_list", "timerange",
|
"exportfilename",
|
||||||
"analysis_rejected", "analysis_to_csv", "analysis_csv_path"]
|
"analysis_groups",
|
||||||
|
"enter_reason_list",
|
||||||
|
"exit_reason_list",
|
||||||
|
"indicator_list",
|
||||||
|
"timerange",
|
||||||
|
"analysis_rejected",
|
||||||
|
"analysis_to_csv",
|
||||||
|
"analysis_csv_path",
|
||||||
|
]
|
||||||
|
|
||||||
NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes",
|
NO_CONF_REQURIED = [
|
||||||
"list-markets", "list-pairs", "list-strategies", "list-freqaimodels",
|
"convert-data",
|
||||||
"list-data", "hyperopt-list", "hyperopt-show", "backtest-filter",
|
"convert-trade-data",
|
||||||
"plot-dataframe", "plot-profit", "show-trades", "trades-to-ohlcv",
|
"download-data",
|
||||||
"strategy-updater"]
|
"list-timeframes",
|
||||||
|
"list-markets",
|
||||||
|
"list-pairs",
|
||||||
|
"list-strategies",
|
||||||
|
"list-freqaimodels",
|
||||||
|
"list-data",
|
||||||
|
"hyperopt-list",
|
||||||
|
"hyperopt-show",
|
||||||
|
"backtest-filter",
|
||||||
|
"plot-dataframe",
|
||||||
|
"plot-profit",
|
||||||
|
"show-trades",
|
||||||
|
"trades-to-ohlcv",
|
||||||
|
"strategy-updater",
|
||||||
|
]
|
||||||
|
|
||||||
NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-strategy"]
|
NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-strategy"]
|
||||||
|
|
||||||
ARGS_STRATEGY_UPDATER = ["strategy_list", "strategy_path", "recursive_strategy_search"]
|
ARGS_STRATEGY_UPDATER = ["strategy_list", "strategy_path", "recursive_strategy_search"]
|
||||||
|
|
||||||
ARGS_LOOKAHEAD_ANALYSIS = [
|
ARGS_LOOKAHEAD_ANALYSIS = [
|
||||||
a for a in ARGS_BACKTEST if a not in ("position_stacking", "use_max_market_positions", 'cache')
|
a for a in ARGS_BACKTEST if a not in ("position_stacking", "use_max_market_positions", "cache")
|
||||||
] + ["minimum_trade_amount", "targeted_trade_amount", "lookahead_analysis_exportfilename"]
|
] + ["minimum_trade_amount", "targeted_trade_amount", "lookahead_analysis_exportfilename"]
|
||||||
|
|
||||||
ARGS_RECURSIVE_ANALYSIS = ["timeframe", "timerange", "dataformat_ohlcv", "pairs", "startup_candle"]
|
ARGS_RECURSIVE_ANALYSIS = ["timeframe", "timerange", "dataformat_ohlcv", "pairs", "startup_candle"]
|
||||||
|
|
||||||
|
@ -156,14 +285,14 @@ class Arguments:
|
||||||
# Workaround issue in argparse with action='append' and default value
|
# Workaround issue in argparse with action='append' and default value
|
||||||
# (see https://bugs.python.org/issue16399)
|
# (see https://bugs.python.org/issue16399)
|
||||||
# Allow no-config for certain commands (like downloading / plotting)
|
# Allow no-config for certain commands (like downloading / plotting)
|
||||||
if ('config' in parsed_arg and parsed_arg.config is None):
|
if "config" in parsed_arg and parsed_arg.config is None:
|
||||||
conf_required = ('command' in parsed_arg and parsed_arg.command in NO_CONF_REQURIED)
|
conf_required = "command" in parsed_arg and parsed_arg.command in NO_CONF_REQURIED
|
||||||
|
|
||||||
if 'user_data_dir' in parsed_arg and parsed_arg.user_data_dir is not None:
|
if "user_data_dir" in parsed_arg and parsed_arg.user_data_dir is not None:
|
||||||
user_dir = parsed_arg.user_data_dir
|
user_dir = parsed_arg.user_data_dir
|
||||||
else:
|
else:
|
||||||
# Default case
|
# Default case
|
||||||
user_dir = 'user_data'
|
user_dir = "user_data"
|
||||||
# Try loading from "user_data/config.json"
|
# Try loading from "user_data/config.json"
|
||||||
cfgfile = Path(user_dir) / DEFAULT_CONFIG
|
cfgfile = Path(user_dir) / DEFAULT_CONFIG
|
||||||
if cfgfile.is_file():
|
if cfgfile.is_file():
|
||||||
|
@ -177,7 +306,6 @@ class Arguments:
|
||||||
return parsed_arg
|
return parsed_arg
|
||||||
|
|
||||||
def _build_args(self, optionlist, parser):
|
def _build_args(self, optionlist, parser):
|
||||||
|
|
||||||
for val in optionlist:
|
for val in optionlist:
|
||||||
opt = AVAILABLE_CLI_OPTIONS[val]
|
opt = AVAILABLE_CLI_OPTIONS[val]
|
||||||
parser.add_argument(*opt.cli, dest=val, **opt.kwargs)
|
parser.add_argument(*opt.cli, dest=val, **opt.kwargs)
|
||||||
|
@ -198,10 +326,9 @@ class Arguments:
|
||||||
|
|
||||||
# Build main command
|
# Build main command
|
||||||
self.parser = argparse.ArgumentParser(
|
self.parser = argparse.ArgumentParser(
|
||||||
prog="freqtrade",
|
prog="freqtrade", description="Free, open source crypto trading bot"
|
||||||
description='Free, open source crypto trading bot'
|
|
||||||
)
|
)
|
||||||
self._build_args(optionlist=['version'], parser=self.parser)
|
self._build_args(optionlist=["version"], parser=self.parser)
|
||||||
|
|
||||||
from freqtrade.commands import (
|
from freqtrade.commands import (
|
||||||
start_analysis_entries_exits,
|
start_analysis_entries_exits,
|
||||||
|
@ -237,24 +364,23 @@ class Arguments:
|
||||||
start_webserver,
|
start_webserver,
|
||||||
)
|
)
|
||||||
|
|
||||||
subparsers = self.parser.add_subparsers(dest='command',
|
subparsers = self.parser.add_subparsers(
|
||||||
# Use custom message when no subhandler is added
|
dest="command",
|
||||||
# shown from `main.py`
|
# Use custom message when no subhandler is added
|
||||||
# required=True
|
# shown from `main.py`
|
||||||
)
|
# required=True
|
||||||
|
)
|
||||||
|
|
||||||
# Add trade subcommand
|
# Add trade subcommand
|
||||||
trade_cmd = subparsers.add_parser(
|
trade_cmd = subparsers.add_parser(
|
||||||
'trade',
|
"trade", help="Trade module.", parents=[_common_parser, _strategy_parser]
|
||||||
help='Trade module.',
|
|
||||||
parents=[_common_parser, _strategy_parser]
|
|
||||||
)
|
)
|
||||||
trade_cmd.set_defaults(func=start_trading)
|
trade_cmd.set_defaults(func=start_trading)
|
||||||
self._build_args(optionlist=ARGS_TRADE, parser=trade_cmd)
|
self._build_args(optionlist=ARGS_TRADE, parser=trade_cmd)
|
||||||
|
|
||||||
# add create-userdir subcommand
|
# add create-userdir subcommand
|
||||||
create_userdir_cmd = subparsers.add_parser(
|
create_userdir_cmd = subparsers.add_parser(
|
||||||
'create-userdir',
|
"create-userdir",
|
||||||
help="Create user-data directory.",
|
help="Create user-data directory.",
|
||||||
)
|
)
|
||||||
create_userdir_cmd.set_defaults(func=start_create_userdir)
|
create_userdir_cmd.set_defaults(func=start_create_userdir)
|
||||||
|
@ -262,7 +388,7 @@ class Arguments:
|
||||||
|
|
||||||
# add new-config subcommand
|
# add new-config subcommand
|
||||||
build_config_cmd = subparsers.add_parser(
|
build_config_cmd = subparsers.add_parser(
|
||||||
'new-config',
|
"new-config",
|
||||||
help="Create new config",
|
help="Create new config",
|
||||||
)
|
)
|
||||||
build_config_cmd.set_defaults(func=start_new_config)
|
build_config_cmd.set_defaults(func=start_new_config)
|
||||||
|
@ -270,7 +396,7 @@ class Arguments:
|
||||||
|
|
||||||
# add show-config subcommand
|
# add show-config subcommand
|
||||||
show_config_cmd = subparsers.add_parser(
|
show_config_cmd = subparsers.add_parser(
|
||||||
'show-config',
|
"show-config",
|
||||||
help="Show resolved config",
|
help="Show resolved config",
|
||||||
)
|
)
|
||||||
show_config_cmd.set_defaults(func=start_show_config)
|
show_config_cmd.set_defaults(func=start_show_config)
|
||||||
|
@ -278,7 +404,7 @@ class Arguments:
|
||||||
|
|
||||||
# add new-strategy subcommand
|
# add new-strategy subcommand
|
||||||
build_strategy_cmd = subparsers.add_parser(
|
build_strategy_cmd = subparsers.add_parser(
|
||||||
'new-strategy',
|
"new-strategy",
|
||||||
help="Create new strategy",
|
help="Create new strategy",
|
||||||
)
|
)
|
||||||
build_strategy_cmd.set_defaults(func=start_new_strategy)
|
build_strategy_cmd.set_defaults(func=start_new_strategy)
|
||||||
|
@ -286,8 +412,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add download-data subcommand
|
# Add download-data subcommand
|
||||||
download_data_cmd = subparsers.add_parser(
|
download_data_cmd = subparsers.add_parser(
|
||||||
'download-data',
|
"download-data",
|
||||||
help='Download backtesting data.',
|
help="Download backtesting data.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
download_data_cmd.set_defaults(func=start_download_data)
|
download_data_cmd.set_defaults(func=start_download_data)
|
||||||
|
@ -295,8 +421,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add convert-data subcommand
|
# Add convert-data subcommand
|
||||||
convert_data_cmd = subparsers.add_parser(
|
convert_data_cmd = subparsers.add_parser(
|
||||||
'convert-data',
|
"convert-data",
|
||||||
help='Convert candle (OHLCV) data from one format to another.',
|
help="Convert candle (OHLCV) data from one format to another.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
convert_data_cmd.set_defaults(func=partial(start_convert_data, ohlcv=True))
|
convert_data_cmd.set_defaults(func=partial(start_convert_data, ohlcv=True))
|
||||||
|
@ -304,8 +430,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add convert-trade-data subcommand
|
# Add convert-trade-data subcommand
|
||||||
convert_trade_data_cmd = subparsers.add_parser(
|
convert_trade_data_cmd = subparsers.add_parser(
|
||||||
'convert-trade-data',
|
"convert-trade-data",
|
||||||
help='Convert trade data from one format to another.',
|
help="Convert trade data from one format to another.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
convert_trade_data_cmd.set_defaults(func=partial(start_convert_data, ohlcv=False))
|
convert_trade_data_cmd.set_defaults(func=partial(start_convert_data, ohlcv=False))
|
||||||
|
@ -313,8 +439,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add trades-to-ohlcv subcommand
|
# Add trades-to-ohlcv subcommand
|
||||||
convert_trade_data_cmd = subparsers.add_parser(
|
convert_trade_data_cmd = subparsers.add_parser(
|
||||||
'trades-to-ohlcv',
|
"trades-to-ohlcv",
|
||||||
help='Convert trade data to OHLCV data.',
|
help="Convert trade data to OHLCV data.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
convert_trade_data_cmd.set_defaults(func=start_convert_trades)
|
convert_trade_data_cmd.set_defaults(func=start_convert_trades)
|
||||||
|
@ -322,8 +448,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add list-data subcommand
|
# Add list-data subcommand
|
||||||
list_data_cmd = subparsers.add_parser(
|
list_data_cmd = subparsers.add_parser(
|
||||||
'list-data',
|
"list-data",
|
||||||
help='List downloaded data.',
|
help="List downloaded data.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
list_data_cmd.set_defaults(func=start_list_data)
|
list_data_cmd.set_defaults(func=start_list_data)
|
||||||
|
@ -331,17 +457,15 @@ class Arguments:
|
||||||
|
|
||||||
# Add backtesting subcommand
|
# Add backtesting subcommand
|
||||||
backtesting_cmd = subparsers.add_parser(
|
backtesting_cmd = subparsers.add_parser(
|
||||||
'backtesting',
|
"backtesting", help="Backtesting module.", parents=[_common_parser, _strategy_parser]
|
||||||
help='Backtesting module.',
|
|
||||||
parents=[_common_parser, _strategy_parser]
|
|
||||||
)
|
)
|
||||||
backtesting_cmd.set_defaults(func=start_backtesting)
|
backtesting_cmd.set_defaults(func=start_backtesting)
|
||||||
self._build_args(optionlist=ARGS_BACKTEST, parser=backtesting_cmd)
|
self._build_args(optionlist=ARGS_BACKTEST, parser=backtesting_cmd)
|
||||||
|
|
||||||
# Add backtesting-show subcommand
|
# Add backtesting-show subcommand
|
||||||
backtesting_show_cmd = subparsers.add_parser(
|
backtesting_show_cmd = subparsers.add_parser(
|
||||||
'backtesting-show',
|
"backtesting-show",
|
||||||
help='Show past Backtest results',
|
help="Show past Backtest results",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
backtesting_show_cmd.set_defaults(func=start_backtesting_show)
|
backtesting_show_cmd.set_defaults(func=start_backtesting_show)
|
||||||
|
@ -349,26 +473,22 @@ class Arguments:
|
||||||
|
|
||||||
# Add backtesting analysis subcommand
|
# Add backtesting analysis subcommand
|
||||||
analysis_cmd = subparsers.add_parser(
|
analysis_cmd = subparsers.add_parser(
|
||||||
'backtesting-analysis',
|
"backtesting-analysis", help="Backtest Analysis module.", parents=[_common_parser]
|
||||||
help='Backtest Analysis module.',
|
|
||||||
parents=[_common_parser]
|
|
||||||
)
|
)
|
||||||
analysis_cmd.set_defaults(func=start_analysis_entries_exits)
|
analysis_cmd.set_defaults(func=start_analysis_entries_exits)
|
||||||
self._build_args(optionlist=ARGS_ANALYZE_ENTRIES_EXITS, parser=analysis_cmd)
|
self._build_args(optionlist=ARGS_ANALYZE_ENTRIES_EXITS, parser=analysis_cmd)
|
||||||
|
|
||||||
# Add edge subcommand
|
# Add edge subcommand
|
||||||
edge_cmd = subparsers.add_parser(
|
edge_cmd = subparsers.add_parser(
|
||||||
'edge',
|
"edge", help="Edge module.", parents=[_common_parser, _strategy_parser]
|
||||||
help='Edge module.',
|
|
||||||
parents=[_common_parser, _strategy_parser]
|
|
||||||
)
|
)
|
||||||
edge_cmd.set_defaults(func=start_edge)
|
edge_cmd.set_defaults(func=start_edge)
|
||||||
self._build_args(optionlist=ARGS_EDGE, parser=edge_cmd)
|
self._build_args(optionlist=ARGS_EDGE, parser=edge_cmd)
|
||||||
|
|
||||||
# Add hyperopt subcommand
|
# Add hyperopt subcommand
|
||||||
hyperopt_cmd = subparsers.add_parser(
|
hyperopt_cmd = subparsers.add_parser(
|
||||||
'hyperopt',
|
"hyperopt",
|
||||||
help='Hyperopt module.',
|
help="Hyperopt module.",
|
||||||
parents=[_common_parser, _strategy_parser],
|
parents=[_common_parser, _strategy_parser],
|
||||||
)
|
)
|
||||||
hyperopt_cmd.set_defaults(func=start_hyperopt)
|
hyperopt_cmd.set_defaults(func=start_hyperopt)
|
||||||
|
@ -376,8 +496,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add hyperopt-list subcommand
|
# Add hyperopt-list subcommand
|
||||||
hyperopt_list_cmd = subparsers.add_parser(
|
hyperopt_list_cmd = subparsers.add_parser(
|
||||||
'hyperopt-list',
|
"hyperopt-list",
|
||||||
help='List Hyperopt results',
|
help="List Hyperopt results",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
hyperopt_list_cmd.set_defaults(func=start_hyperopt_list)
|
hyperopt_list_cmd.set_defaults(func=start_hyperopt_list)
|
||||||
|
@ -385,8 +505,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add hyperopt-show subcommand
|
# Add hyperopt-show subcommand
|
||||||
hyperopt_show_cmd = subparsers.add_parser(
|
hyperopt_show_cmd = subparsers.add_parser(
|
||||||
'hyperopt-show',
|
"hyperopt-show",
|
||||||
help='Show details of Hyperopt results',
|
help="Show details of Hyperopt results",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
hyperopt_show_cmd.set_defaults(func=start_hyperopt_show)
|
hyperopt_show_cmd.set_defaults(func=start_hyperopt_show)
|
||||||
|
@ -394,8 +514,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add list-exchanges subcommand
|
# Add list-exchanges subcommand
|
||||||
list_exchanges_cmd = subparsers.add_parser(
|
list_exchanges_cmd = subparsers.add_parser(
|
||||||
'list-exchanges',
|
"list-exchanges",
|
||||||
help='Print available exchanges.',
|
help="Print available exchanges.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
list_exchanges_cmd.set_defaults(func=start_list_exchanges)
|
list_exchanges_cmd.set_defaults(func=start_list_exchanges)
|
||||||
|
@ -403,8 +523,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add list-markets subcommand
|
# Add list-markets subcommand
|
||||||
list_markets_cmd = subparsers.add_parser(
|
list_markets_cmd = subparsers.add_parser(
|
||||||
'list-markets',
|
"list-markets",
|
||||||
help='Print markets on exchange.',
|
help="Print markets on exchange.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
list_markets_cmd.set_defaults(func=partial(start_list_markets, pairs_only=False))
|
list_markets_cmd.set_defaults(func=partial(start_list_markets, pairs_only=False))
|
||||||
|
@ -412,8 +532,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add list-pairs subcommand
|
# Add list-pairs subcommand
|
||||||
list_pairs_cmd = subparsers.add_parser(
|
list_pairs_cmd = subparsers.add_parser(
|
||||||
'list-pairs',
|
"list-pairs",
|
||||||
help='Print pairs on exchange.',
|
help="Print pairs on exchange.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
list_pairs_cmd.set_defaults(func=partial(start_list_markets, pairs_only=True))
|
list_pairs_cmd.set_defaults(func=partial(start_list_markets, pairs_only=True))
|
||||||
|
@ -421,8 +541,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add list-strategies subcommand
|
# Add list-strategies subcommand
|
||||||
list_strategies_cmd = subparsers.add_parser(
|
list_strategies_cmd = subparsers.add_parser(
|
||||||
'list-strategies',
|
"list-strategies",
|
||||||
help='Print available strategies.',
|
help="Print available strategies.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
list_strategies_cmd.set_defaults(func=start_list_strategies)
|
list_strategies_cmd.set_defaults(func=start_list_strategies)
|
||||||
|
@ -430,8 +550,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add list-freqAI Models subcommand
|
# Add list-freqAI Models subcommand
|
||||||
list_freqaimodels_cmd = subparsers.add_parser(
|
list_freqaimodels_cmd = subparsers.add_parser(
|
||||||
'list-freqaimodels',
|
"list-freqaimodels",
|
||||||
help='Print available freqAI models.',
|
help="Print available freqAI models.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
list_freqaimodels_cmd.set_defaults(func=start_list_freqAI_models)
|
list_freqaimodels_cmd.set_defaults(func=start_list_freqAI_models)
|
||||||
|
@ -439,8 +559,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add list-timeframes subcommand
|
# Add list-timeframes subcommand
|
||||||
list_timeframes_cmd = subparsers.add_parser(
|
list_timeframes_cmd = subparsers.add_parser(
|
||||||
'list-timeframes',
|
"list-timeframes",
|
||||||
help='Print available timeframes for the exchange.',
|
help="Print available timeframes for the exchange.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
list_timeframes_cmd.set_defaults(func=start_list_timeframes)
|
list_timeframes_cmd.set_defaults(func=start_list_timeframes)
|
||||||
|
@ -448,8 +568,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add show-trades subcommand
|
# Add show-trades subcommand
|
||||||
show_trades = subparsers.add_parser(
|
show_trades = subparsers.add_parser(
|
||||||
'show-trades',
|
"show-trades",
|
||||||
help='Show trades.',
|
help="Show trades.",
|
||||||
parents=[_common_parser],
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
show_trades.set_defaults(func=start_show_trades)
|
show_trades.set_defaults(func=start_show_trades)
|
||||||
|
@ -457,8 +577,8 @@ class Arguments:
|
||||||
|
|
||||||
# Add test-pairlist subcommand
|
# Add test-pairlist subcommand
|
||||||
test_pairlist_cmd = subparsers.add_parser(
|
test_pairlist_cmd = subparsers.add_parser(
|
||||||
'test-pairlist',
|
"test-pairlist",
|
||||||
help='Test your pairlist configuration.',
|
help="Test your pairlist configuration.",
|
||||||
)
|
)
|
||||||
test_pairlist_cmd.set_defaults(func=start_test_pairlist)
|
test_pairlist_cmd.set_defaults(func=start_test_pairlist)
|
||||||
self._build_args(optionlist=ARGS_TEST_PAIRLIST, parser=test_pairlist_cmd)
|
self._build_args(optionlist=ARGS_TEST_PAIRLIST, parser=test_pairlist_cmd)
|
||||||
|
@ -473,16 +593,16 @@ class Arguments:
|
||||||
|
|
||||||
# Add install-ui subcommand
|
# Add install-ui subcommand
|
||||||
install_ui_cmd = subparsers.add_parser(
|
install_ui_cmd = subparsers.add_parser(
|
||||||
'install-ui',
|
"install-ui",
|
||||||
help='Install FreqUI',
|
help="Install FreqUI",
|
||||||
)
|
)
|
||||||
install_ui_cmd.set_defaults(func=start_install_ui)
|
install_ui_cmd.set_defaults(func=start_install_ui)
|
||||||
self._build_args(optionlist=ARGS_INSTALL_UI, parser=install_ui_cmd)
|
self._build_args(optionlist=ARGS_INSTALL_UI, parser=install_ui_cmd)
|
||||||
|
|
||||||
# Add Plotting subcommand
|
# Add Plotting subcommand
|
||||||
plot_dataframe_cmd = subparsers.add_parser(
|
plot_dataframe_cmd = subparsers.add_parser(
|
||||||
'plot-dataframe',
|
"plot-dataframe",
|
||||||
help='Plot candles with indicators.',
|
help="Plot candles with indicators.",
|
||||||
parents=[_common_parser, _strategy_parser],
|
parents=[_common_parser, _strategy_parser],
|
||||||
)
|
)
|
||||||
plot_dataframe_cmd.set_defaults(func=start_plot_dataframe)
|
plot_dataframe_cmd.set_defaults(func=start_plot_dataframe)
|
||||||
|
@ -490,8 +610,8 @@ class Arguments:
|
||||||
|
|
||||||
# Plot profit
|
# Plot profit
|
||||||
plot_profit_cmd = subparsers.add_parser(
|
plot_profit_cmd = subparsers.add_parser(
|
||||||
'plot-profit',
|
"plot-profit",
|
||||||
help='Generate plot showing profits.',
|
help="Generate plot showing profits.",
|
||||||
parents=[_common_parser, _strategy_parser],
|
parents=[_common_parser, _strategy_parser],
|
||||||
)
|
)
|
||||||
plot_profit_cmd.set_defaults(func=start_plot_profit)
|
plot_profit_cmd.set_defaults(func=start_plot_profit)
|
||||||
|
@ -499,40 +619,36 @@ class Arguments:
|
||||||
|
|
||||||
# Add webserver subcommand
|
# Add webserver subcommand
|
||||||
webserver_cmd = subparsers.add_parser(
|
webserver_cmd = subparsers.add_parser(
|
||||||
'webserver',
|
"webserver", help="Webserver module.", parents=[_common_parser]
|
||||||
help='Webserver module.',
|
|
||||||
parents=[_common_parser]
|
|
||||||
)
|
)
|
||||||
webserver_cmd.set_defaults(func=start_webserver)
|
webserver_cmd.set_defaults(func=start_webserver)
|
||||||
self._build_args(optionlist=ARGS_WEBSERVER, parser=webserver_cmd)
|
self._build_args(optionlist=ARGS_WEBSERVER, parser=webserver_cmd)
|
||||||
|
|
||||||
# Add strategy_updater subcommand
|
# Add strategy_updater subcommand
|
||||||
strategy_updater_cmd = subparsers.add_parser(
|
strategy_updater_cmd = subparsers.add_parser(
|
||||||
'strategy-updater',
|
"strategy-updater",
|
||||||
help='updates outdated strategy files to the current version',
|
help="updates outdated strategy files to the current version",
|
||||||
parents=[_common_parser]
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
strategy_updater_cmd.set_defaults(func=start_strategy_update)
|
strategy_updater_cmd.set_defaults(func=start_strategy_update)
|
||||||
self._build_args(optionlist=ARGS_STRATEGY_UPDATER, parser=strategy_updater_cmd)
|
self._build_args(optionlist=ARGS_STRATEGY_UPDATER, parser=strategy_updater_cmd)
|
||||||
|
|
||||||
# Add lookahead_analysis subcommand
|
# Add lookahead_analysis subcommand
|
||||||
lookahead_analayis_cmd = subparsers.add_parser(
|
lookahead_analayis_cmd = subparsers.add_parser(
|
||||||
'lookahead-analysis',
|
"lookahead-analysis",
|
||||||
help="Check for potential look ahead bias.",
|
help="Check for potential look ahead bias.",
|
||||||
parents=[_common_parser, _strategy_parser]
|
parents=[_common_parser, _strategy_parser],
|
||||||
)
|
)
|
||||||
lookahead_analayis_cmd.set_defaults(func=start_lookahead_analysis)
|
lookahead_analayis_cmd.set_defaults(func=start_lookahead_analysis)
|
||||||
|
|
||||||
self._build_args(optionlist=ARGS_LOOKAHEAD_ANALYSIS,
|
self._build_args(optionlist=ARGS_LOOKAHEAD_ANALYSIS, parser=lookahead_analayis_cmd)
|
||||||
parser=lookahead_analayis_cmd)
|
|
||||||
|
|
||||||
# Add recursive_analysis subcommand
|
# Add recursive_analysis subcommand
|
||||||
recursive_analayis_cmd = subparsers.add_parser(
|
recursive_analayis_cmd = subparsers.add_parser(
|
||||||
'recursive-analysis',
|
"recursive-analysis",
|
||||||
help="Check for potential recursive formula issue.",
|
help="Check for potential recursive formula issue.",
|
||||||
parents=[_common_parser, _strategy_parser]
|
parents=[_common_parser, _strategy_parser],
|
||||||
)
|
)
|
||||||
recursive_analayis_cmd.set_defaults(func=start_recursive_analysis)
|
recursive_analayis_cmd.set_defaults(func=start_recursive_analysis)
|
||||||
|
|
||||||
self._build_args(optionlist=ARGS_RECURSIVE_ANALYSIS,
|
self._build_args(optionlist=ARGS_RECURSIVE_ANALYSIS, parser=recursive_analayis_cmd)
|
||||||
parser=recursive_analayis_cmd)
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ def ask_user_overwrite(config_path: Path) -> bool:
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
answers = prompt(questions)
|
answers = prompt(questions)
|
||||||
return answers['overwrite']
|
return answers["overwrite"]
|
||||||
|
|
||||||
|
|
||||||
def ask_user_config() -> Dict[str, Any]:
|
def ask_user_config() -> Dict[str, Any]:
|
||||||
|
@ -65,7 +65,7 @@ def ask_user_config() -> Dict[str, Any]:
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"name": "stake_currency",
|
"name": "stake_currency",
|
||||||
"message": "Please insert your stake currency:",
|
"message": "Please insert your stake currency:",
|
||||||
"default": 'USDT',
|
"default": "USDT",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
@ -75,34 +75,33 @@ def ask_user_config() -> Dict[str, Any]:
|
||||||
"validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val),
|
"validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val),
|
||||||
"filter": lambda val: '"' + UNLIMITED_STAKE_AMOUNT + '"'
|
"filter": lambda val: '"' + UNLIMITED_STAKE_AMOUNT + '"'
|
||||||
if val == UNLIMITED_STAKE_AMOUNT
|
if val == UNLIMITED_STAKE_AMOUNT
|
||||||
else val
|
else val,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"name": "max_open_trades",
|
"name": "max_open_trades",
|
||||||
"message": "Please insert max_open_trades (Integer or -1 for unlimited open trades):",
|
"message": "Please insert max_open_trades (Integer or -1 for unlimited open trades):",
|
||||||
"default": "3",
|
"default": "3",
|
||||||
"validate": lambda val: validate_is_int(val)
|
"validate": lambda val: validate_is_int(val),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "select",
|
"type": "select",
|
||||||
"name": "timeframe_in_config",
|
"name": "timeframe_in_config",
|
||||||
"message": "Time",
|
"message": "Time",
|
||||||
"choices": ["Have the strategy define timeframe.", "Override in configuration."]
|
"choices": ["Have the strategy define timeframe.", "Override in configuration."],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"name": "timeframe",
|
"name": "timeframe",
|
||||||
"message": "Please insert your desired timeframe (e.g. 5m):",
|
"message": "Please insert your desired timeframe (e.g. 5m):",
|
||||||
"default": "5m",
|
"default": "5m",
|
||||||
"when": lambda x: x["timeframe_in_config"] == 'Override in configuration.'
|
"when": lambda x: x["timeframe_in_config"] == "Override in configuration.",
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"name": "fiat_display_currency",
|
"name": "fiat_display_currency",
|
||||||
"message": "Please insert your display Currency (for reporting):",
|
"message": "Please insert your display Currency (for reporting):",
|
||||||
"default": 'USD',
|
"default": "USD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "select",
|
"type": "select",
|
||||||
|
@ -125,33 +124,33 @@ def ask_user_config() -> Dict[str, Any]:
|
||||||
"name": "trading_mode",
|
"name": "trading_mode",
|
||||||
"message": "Do you want to trade Perpetual Swaps (perpetual futures)?",
|
"message": "Do you want to trade Perpetual Swaps (perpetual futures)?",
|
||||||
"default": False,
|
"default": False,
|
||||||
"filter": lambda val: 'futures' if val else 'spot',
|
"filter": lambda val: "futures" if val else "spot",
|
||||||
"when": lambda x: x["exchange_name"] in ['binance', 'gate', 'okx'],
|
"when": lambda x: x["exchange_name"] in ["binance", "gate", "okx"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "autocomplete",
|
"type": "autocomplete",
|
||||||
"name": "exchange_name",
|
"name": "exchange_name",
|
||||||
"message": "Type your exchange name (Must be supported by ccxt)",
|
"message": "Type your exchange name (Must be supported by ccxt)",
|
||||||
"choices": available_exchanges(),
|
"choices": available_exchanges(),
|
||||||
"when": lambda x: x["exchange_name"] == 'other'
|
"when": lambda x: x["exchange_name"] == "other",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"name": "exchange_key",
|
"name": "exchange_key",
|
||||||
"message": "Insert Exchange Key",
|
"message": "Insert Exchange Key",
|
||||||
"when": lambda x: not x['dry_run']
|
"when": lambda x: not x["dry_run"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"name": "exchange_secret",
|
"name": "exchange_secret",
|
||||||
"message": "Insert Exchange Secret",
|
"message": "Insert Exchange Secret",
|
||||||
"when": lambda x: not x['dry_run']
|
"when": lambda x: not x["dry_run"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"name": "exchange_key_password",
|
"name": "exchange_key_password",
|
||||||
"message": "Insert Exchange API Key password",
|
"message": "Insert Exchange API Key password",
|
||||||
"when": lambda x: not x['dry_run'] and x['exchange_name'] in ('kucoin', 'okx')
|
"when": lambda x: not x["dry_run"] and x["exchange_name"] in ("kucoin", "okx"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "confirm",
|
"type": "confirm",
|
||||||
|
@ -163,13 +162,13 @@ def ask_user_config() -> Dict[str, Any]:
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"name": "telegram_token",
|
"name": "telegram_token",
|
||||||
"message": "Insert Telegram token",
|
"message": "Insert Telegram token",
|
||||||
"when": lambda x: x['telegram']
|
"when": lambda x: x["telegram"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"name": "telegram_chat_id",
|
"name": "telegram_chat_id",
|
||||||
"message": "Insert Telegram chat id",
|
"message": "Insert Telegram chat id",
|
||||||
"when": lambda x: x['telegram']
|
"when": lambda x: x["telegram"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "confirm",
|
"type": "confirm",
|
||||||
|
@ -180,23 +179,25 @@ def ask_user_config() -> Dict[str, Any]:
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"name": "api_server_listen_addr",
|
"name": "api_server_listen_addr",
|
||||||
"message": ("Insert Api server Listen Address (0.0.0.0 for docker, "
|
"message": (
|
||||||
"otherwise best left untouched)"),
|
"Insert Api server Listen Address (0.0.0.0 for docker, "
|
||||||
|
"otherwise best left untouched)"
|
||||||
|
),
|
||||||
"default": "127.0.0.1" if not running_in_docker() else "0.0.0.0",
|
"default": "127.0.0.1" if not running_in_docker() else "0.0.0.0",
|
||||||
"when": lambda x: x['api_server']
|
"when": lambda x: x["api_server"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"name": "api_server_username",
|
"name": "api_server_username",
|
||||||
"message": "Insert api-server username",
|
"message": "Insert api-server username",
|
||||||
"default": "freqtrader",
|
"default": "freqtrader",
|
||||||
"when": lambda x: x['api_server']
|
"when": lambda x: x["api_server"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"name": "api_server_password",
|
"name": "api_server_password",
|
||||||
"message": "Insert api-server password",
|
"message": "Insert api-server password",
|
||||||
"when": lambda x: x['api_server']
|
"when": lambda x: x["api_server"],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
answers = prompt(questions)
|
answers = prompt(questions)
|
||||||
|
@ -205,15 +206,11 @@ def ask_user_config() -> Dict[str, Any]:
|
||||||
# Interrupted questionary sessions return an empty dict.
|
# Interrupted questionary sessions return an empty dict.
|
||||||
raise OperationalException("User interrupted interactive questions.")
|
raise OperationalException("User interrupted interactive questions.")
|
||||||
# Ensure default is set for non-futures exchanges
|
# Ensure default is set for non-futures exchanges
|
||||||
answers['trading_mode'] = answers.get('trading_mode', "spot")
|
answers["trading_mode"] = answers.get("trading_mode", "spot")
|
||||||
answers['margin_mode'] = (
|
answers["margin_mode"] = "isolated" if answers.get("trading_mode") == "futures" else ""
|
||||||
'isolated'
|
|
||||||
if answers.get('trading_mode') == 'futures'
|
|
||||||
else ''
|
|
||||||
)
|
|
||||||
# Force JWT token to be a random string
|
# Force JWT token to be a random string
|
||||||
answers['api_server_jwt_key'] = secrets.token_hex()
|
answers["api_server_jwt_key"] = secrets.token_hex()
|
||||||
answers['api_server_ws_token'] = secrets.token_urlsafe(25)
|
answers["api_server_ws_token"] = secrets.token_urlsafe(25)
|
||||||
|
|
||||||
return answers
|
return answers
|
||||||
|
|
||||||
|
@ -225,26 +222,26 @@ def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None:
|
||||||
:param selections: Dict containing selections taken by the user.
|
:param selections: Dict containing selections taken by the user.
|
||||||
"""
|
"""
|
||||||
from jinja2.exceptions import TemplateNotFound
|
from jinja2.exceptions import TemplateNotFound
|
||||||
|
|
||||||
try:
|
try:
|
||||||
exchange_template = MAP_EXCHANGE_CHILDCLASS.get(
|
exchange_template = MAP_EXCHANGE_CHILDCLASS.get(
|
||||||
selections['exchange_name'], selections['exchange_name'])
|
selections["exchange_name"], selections["exchange_name"]
|
||||||
|
)
|
||||||
|
|
||||||
selections['exchange'] = render_template(
|
selections["exchange"] = render_template(
|
||||||
templatefile=f"subtemplates/exchange_{exchange_template}.j2",
|
templatefile=f"subtemplates/exchange_{exchange_template}.j2", arguments=selections
|
||||||
arguments=selections
|
|
||||||
)
|
)
|
||||||
except TemplateNotFound:
|
except TemplateNotFound:
|
||||||
selections['exchange'] = render_template(
|
selections["exchange"] = render_template(
|
||||||
templatefile="subtemplates/exchange_generic.j2",
|
templatefile="subtemplates/exchange_generic.j2", arguments=selections
|
||||||
arguments=selections
|
|
||||||
)
|
)
|
||||||
|
|
||||||
config_text = render_template(templatefile='base_config.json.j2',
|
config_text = render_template(templatefile="base_config.json.j2", arguments=selections)
|
||||||
arguments=selections)
|
|
||||||
|
|
||||||
logger.info(f"Writing config to `{config_path}`.")
|
logger.info(f"Writing config to `{config_path}`.")
|
||||||
logger.info(
|
logger.info(
|
||||||
"Please make sure to check the configuration contents and adjust settings to your needs.")
|
"Please make sure to check the configuration contents and adjust settings to your needs."
|
||||||
|
)
|
||||||
|
|
||||||
config_path.write_text(config_text)
|
config_path.write_text(config_text)
|
||||||
|
|
||||||
|
@ -255,7 +252,7 @@ def start_new_config(args: Dict[str, Any]) -> None:
|
||||||
Asking the user questions to fill out the template accordingly.
|
Asking the user questions to fill out the template accordingly.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config_path = Path(args['config'][0])
|
config_path = Path(args["config"][0])
|
||||||
chown_user_directory(config_path.parent)
|
chown_user_directory(config_path.parent)
|
||||||
if config_path.exists():
|
if config_path.exists():
|
||||||
overwrite = ask_user_overwrite(config_path)
|
overwrite = ask_user_overwrite(config_path)
|
||||||
|
@ -264,22 +261,22 @@ def start_new_config(args: Dict[str, Any]) -> None:
|
||||||
else:
|
else:
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f"Configuration file `{config_path}` already exists. "
|
f"Configuration file `{config_path}` already exists. "
|
||||||
"Please delete it or use a different configuration file name.")
|
"Please delete it or use a different configuration file name."
|
||||||
|
)
|
||||||
selections = ask_user_config()
|
selections = ask_user_config()
|
||||||
deploy_new_config(config_path, selections)
|
deploy_new_config(config_path, selections)
|
||||||
|
|
||||||
|
|
||||||
def start_show_config(args: Dict[str, Any]) -> None:
|
def start_show_config(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE, set_dry=False)
|
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE, set_dry=False)
|
||||||
|
|
||||||
# TODO: Sanitize from sensitive info before printing
|
# TODO: Sanitize from sensitive info before printing
|
||||||
|
|
||||||
print("Your combined configuration is:")
|
print("Your combined configuration is:")
|
||||||
config_sanitized = sanitize_config(
|
config_sanitized = sanitize_config(
|
||||||
config['original_config'],
|
config["original_config"], show_sensitive=args.get("show_sensitive", False)
|
||||||
show_sensitive=args.get('show_sensitive', False)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from rich import print_json
|
from rich import print_json
|
||||||
|
|
||||||
print_json(data=config_sanitized)
|
print_json(data=config_sanitized)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,14 +23,17 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _check_data_config_download_sanity(config: Config) -> None:
|
def _check_data_config_download_sanity(config: Config) -> None:
|
||||||
if 'days' in config and 'timerange' in config:
|
if "days" in config and "timerange" in config:
|
||||||
raise ConfigurationError("--days and --timerange are mutually exclusive. "
|
raise ConfigurationError(
|
||||||
"You can only specify one or the other.")
|
"--days and --timerange are mutually exclusive. "
|
||||||
|
"You can only specify one or the other."
|
||||||
|
)
|
||||||
|
|
||||||
if 'pairs' not in config:
|
if "pairs" not in config:
|
||||||
raise ConfigurationError(
|
raise ConfigurationError(
|
||||||
"Downloading data requires a list of pairs. "
|
"Downloading data requires a list of pairs. "
|
||||||
"Please check the documentation on how to configure this.")
|
"Please check the documentation on how to configure this."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def start_download_data(args: Dict[str, Any]) -> None:
|
def start_download_data(args: Dict[str, Any]) -> None:
|
||||||
|
@ -49,38 +52,41 @@ def start_download_data(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
|
|
||||||
def start_convert_trades(args: Dict[str, Any]) -> None:
|
def start_convert_trades(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
||||||
|
|
||||||
timerange = TimeRange()
|
timerange = TimeRange()
|
||||||
|
|
||||||
# Remove stake-currency to skip checks which are not relevant for datadownload
|
# Remove stake-currency to skip checks which are not relevant for datadownload
|
||||||
config['stake_currency'] = ''
|
config["stake_currency"] = ""
|
||||||
|
|
||||||
if 'timeframes' not in config:
|
if "timeframes" not in config:
|
||||||
config['timeframes'] = DL_DATA_TIMEFRAMES
|
config["timeframes"] = DL_DATA_TIMEFRAMES
|
||||||
|
|
||||||
# Init exchange
|
# Init exchange
|
||||||
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
||||||
# Manual validations of relevant settings
|
# Manual validations of relevant settings
|
||||||
|
|
||||||
for timeframe in config['timeframes']:
|
for timeframe in config["timeframes"]:
|
||||||
exchange.validate_timeframes(timeframe)
|
exchange.validate_timeframes(timeframe)
|
||||||
available_pairs = [
|
available_pairs = [
|
||||||
p for p in exchange.get_markets(
|
p
|
||||||
tradable_only=True, active_only=not config.get('include_inactive')
|
for p in exchange.get_markets(
|
||||||
).keys()
|
tradable_only=True, active_only=not config.get("include_inactive")
|
||||||
|
).keys()
|
||||||
]
|
]
|
||||||
|
|
||||||
expanded_pairs = dynamic_expand_pairlist(config, available_pairs)
|
expanded_pairs = dynamic_expand_pairlist(config, available_pairs)
|
||||||
|
|
||||||
# Convert downloaded trade data to different timeframes
|
# Convert downloaded trade data to different timeframes
|
||||||
convert_trades_to_ohlcv(
|
convert_trades_to_ohlcv(
|
||||||
pairs=expanded_pairs, timeframes=config['timeframes'],
|
pairs=expanded_pairs,
|
||||||
datadir=config['datadir'], timerange=timerange, erase=bool(config.get('erase')),
|
timeframes=config["timeframes"],
|
||||||
data_format_ohlcv=config['dataformat_ohlcv'],
|
datadir=config["datadir"],
|
||||||
data_format_trades=config['dataformat_trades'],
|
timerange=timerange,
|
||||||
candle_type=config.get('candle_type_def', CandleType.SPOT)
|
erase=bool(config.get("erase")),
|
||||||
|
data_format_ohlcv=config["dataformat_ohlcv"],
|
||||||
|
data_format_trades=config["dataformat_trades"],
|
||||||
|
candle_type=config.get("candle_type_def", CandleType.SPOT),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,14 +97,19 @@ def start_convert_data(args: Dict[str, Any], ohlcv: bool = True) -> None:
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
if ohlcv:
|
if ohlcv:
|
||||||
migrate_data(config)
|
migrate_data(config)
|
||||||
convert_ohlcv_format(config,
|
convert_ohlcv_format(
|
||||||
convert_from=args['format_from'],
|
config,
|
||||||
convert_to=args['format_to'],
|
convert_from=args["format_from"],
|
||||||
erase=args['erase'])
|
convert_to=args["format_to"],
|
||||||
|
erase=args["erase"],
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
convert_trades_format(config,
|
convert_trades_format(
|
||||||
convert_from=args['format_from_trades'], convert_to=args['format_to'],
|
config,
|
||||||
erase=args['erase'])
|
convert_from=args["format_from_trades"],
|
||||||
|
convert_to=args["format_to"],
|
||||||
|
erase=args["erase"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def start_list_data(args: Dict[str, Any]) -> None:
|
def start_list_data(args: Dict[str, Any]) -> None:
|
||||||
|
@ -111,45 +122,59 @@ def start_list_data(args: Dict[str, Any]) -> None:
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
from freqtrade.data.history import get_datahandler
|
from freqtrade.data.history import get_datahandler
|
||||||
dhc = get_datahandler(config['datadir'], config['dataformat_ohlcv'])
|
|
||||||
|
dhc = get_datahandler(config["datadir"], config["dataformat_ohlcv"])
|
||||||
|
|
||||||
paircombs = dhc.ohlcv_get_available_data(
|
paircombs = dhc.ohlcv_get_available_data(
|
||||||
config['datadir'],
|
config["datadir"], config.get("trading_mode", TradingMode.SPOT)
|
||||||
config.get('trading_mode', TradingMode.SPOT)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if args['pairs']:
|
if args["pairs"]:
|
||||||
paircombs = [comb for comb in paircombs if comb[0] in args['pairs']]
|
paircombs = [comb for comb in paircombs if comb[0] in args["pairs"]]
|
||||||
|
|
||||||
print(f"Found {len(paircombs)} pair / timeframe combinations.")
|
print(f"Found {len(paircombs)} pair / timeframe combinations.")
|
||||||
if not config.get('show_timerange'):
|
if not config.get("show_timerange"):
|
||||||
groupedpair = defaultdict(list)
|
groupedpair = defaultdict(list)
|
||||||
for pair, timeframe, candle_type in sorted(
|
for pair, timeframe, candle_type in sorted(
|
||||||
paircombs,
|
paircombs, key=lambda x: (x[0], timeframe_to_minutes(x[1]), x[2])
|
||||||
key=lambda x: (x[0], timeframe_to_minutes(x[1]), x[2])
|
|
||||||
):
|
):
|
||||||
groupedpair[(pair, candle_type)].append(timeframe)
|
groupedpair[(pair, candle_type)].append(timeframe)
|
||||||
|
|
||||||
if groupedpair:
|
if groupedpair:
|
||||||
print(tabulate([
|
print(
|
||||||
(pair, ', '.join(timeframes), candle_type)
|
tabulate(
|
||||||
for (pair, candle_type), timeframes in groupedpair.items()
|
[
|
||||||
],
|
(pair, ", ".join(timeframes), candle_type)
|
||||||
headers=("Pair", "Timeframe", "Type"),
|
for (pair, candle_type), timeframes in groupedpair.items()
|
||||||
tablefmt='psql', stralign='right'))
|
],
|
||||||
|
headers=("Pair", "Timeframe", "Type"),
|
||||||
|
tablefmt="psql",
|
||||||
|
stralign="right",
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
paircombs1 = [(
|
paircombs1 = [
|
||||||
pair, timeframe, candle_type,
|
(pair, timeframe, candle_type, *dhc.ohlcv_data_min_max(pair, timeframe, candle_type))
|
||||||
*dhc.ohlcv_data_min_max(pair, timeframe, candle_type)
|
for pair, timeframe, candle_type in paircombs
|
||||||
) for pair, timeframe, candle_type in paircombs]
|
]
|
||||||
|
|
||||||
print(tabulate([
|
print(
|
||||||
(pair, timeframe, candle_type,
|
tabulate(
|
||||||
start.strftime(DATETIME_PRINT_FORMAT),
|
[
|
||||||
end.strftime(DATETIME_PRINT_FORMAT), length)
|
(
|
||||||
for pair, timeframe, candle_type, start, end, length in sorted(
|
pair,
|
||||||
paircombs1,
|
timeframe,
|
||||||
key=lambda x: (x[0], timeframe_to_minutes(x[1]), x[2]))
|
candle_type,
|
||||||
],
|
start.strftime(DATETIME_PRINT_FORMAT),
|
||||||
headers=("Pair", "Timeframe", "Type", 'From', 'To', 'Candles'),
|
end.strftime(DATETIME_PRINT_FORMAT),
|
||||||
tablefmt='psql', stralign='right'))
|
length,
|
||||||
|
)
|
||||||
|
for pair, timeframe, candle_type, start, end, length in sorted(
|
||||||
|
paircombs1, key=lambda x: (x[0], timeframe_to_minutes(x[1]), x[2])
|
||||||
|
)
|
||||||
|
],
|
||||||
|
headers=("Pair", "Timeframe", "Type", "From", "To", "Candles"),
|
||||||
|
tablefmt="psql",
|
||||||
|
stralign="right",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -19,9 +19,9 @@ def start_convert_db(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
|
|
||||||
init_db(config['db_url'])
|
init_db(config["db_url"])
|
||||||
session_target = Trade.session
|
session_target = Trade.session
|
||||||
init_db(config['db_url_from'])
|
init_db(config["db_url_from"])
|
||||||
logger.info("Starting db migration.")
|
logger.info("Starting db migration.")
|
||||||
|
|
||||||
trade_count = 0
|
trade_count = 0
|
||||||
|
@ -47,9 +47,11 @@ def start_convert_db(args: Dict[str, Any]) -> None:
|
||||||
max_order_id = session_target.scalar(select(func.max(Order.id)))
|
max_order_id = session_target.scalar(select(func.max(Order.id)))
|
||||||
max_pairlock_id = session_target.scalar(select(func.max(PairLock.id)))
|
max_pairlock_id = session_target.scalar(select(func.max(PairLock.id)))
|
||||||
|
|
||||||
set_sequence_ids(session_target.get_bind(),
|
set_sequence_ids(
|
||||||
trade_id=max_trade_id,
|
session_target.get_bind(),
|
||||||
order_id=max_order_id,
|
trade_id=max_trade_id,
|
||||||
pairlock_id=max_pairlock_id)
|
order_id=max_order_id,
|
||||||
|
pairlock_id=max_pairlock_id,
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(f"Migrated {trade_count} Trades, and {pairlock_count} Pairlocks.")
|
logger.info(f"Migrated {trade_count} Trades, and {pairlock_count} Pairlocks.")
|
||||||
|
|
|
@ -38,7 +38,7 @@ def deploy_new_strategy(strategy_name: str, strategy_path: Path, subtemplate: st
|
||||||
"""
|
"""
|
||||||
Deploy new strategy from template to strategy_path
|
Deploy new strategy from template to strategy_path
|
||||||
"""
|
"""
|
||||||
fallback = 'full'
|
fallback = "full"
|
||||||
attributes = render_template_with_fallback(
|
attributes = render_template_with_fallback(
|
||||||
templatefile=f"strategy_subtemplates/strategy_attributes_{subtemplate}.j2",
|
templatefile=f"strategy_subtemplates/strategy_attributes_{subtemplate}.j2",
|
||||||
templatefallbackfile=f"strategy_subtemplates/strategy_attributes_{fallback}.j2",
|
templatefallbackfile=f"strategy_subtemplates/strategy_attributes_{fallback}.j2",
|
||||||
|
@ -64,33 +64,35 @@ def deploy_new_strategy(strategy_name: str, strategy_path: Path, subtemplate: st
|
||||||
templatefallbackfile="strategy_subtemplates/strategy_methods_empty.j2",
|
templatefallbackfile="strategy_subtemplates/strategy_methods_empty.j2",
|
||||||
)
|
)
|
||||||
|
|
||||||
strategy_text = render_template(templatefile='base_strategy.py.j2',
|
strategy_text = render_template(
|
||||||
arguments={"strategy": strategy_name,
|
templatefile="base_strategy.py.j2",
|
||||||
"attributes": attributes,
|
arguments={
|
||||||
"indicators": indicators,
|
"strategy": strategy_name,
|
||||||
"buy_trend": buy_trend,
|
"attributes": attributes,
|
||||||
"sell_trend": sell_trend,
|
"indicators": indicators,
|
||||||
"plot_config": plot_config,
|
"buy_trend": buy_trend,
|
||||||
"additional_methods": additional_methods,
|
"sell_trend": sell_trend,
|
||||||
})
|
"plot_config": plot_config,
|
||||||
|
"additional_methods": additional_methods,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(f"Writing strategy to `{strategy_path}`.")
|
logger.info(f"Writing strategy to `{strategy_path}`.")
|
||||||
strategy_path.write_text(strategy_text)
|
strategy_path.write_text(strategy_text)
|
||||||
|
|
||||||
|
|
||||||
def start_new_strategy(args: Dict[str, Any]) -> None:
|
def start_new_strategy(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
|
|
||||||
if "strategy" in args and args["strategy"]:
|
if "strategy" in args and args["strategy"]:
|
||||||
|
new_path = config["user_data_dir"] / USERPATH_STRATEGIES / (args["strategy"] + ".py")
|
||||||
new_path = config['user_data_dir'] / USERPATH_STRATEGIES / (args['strategy'] + '.py')
|
|
||||||
|
|
||||||
if new_path.exists():
|
if new_path.exists():
|
||||||
raise OperationalException(f"`{new_path}` already exists. "
|
raise OperationalException(
|
||||||
"Please choose another Strategy Name.")
|
f"`{new_path}` already exists. " "Please choose another Strategy Name."
|
||||||
|
)
|
||||||
|
|
||||||
deploy_new_strategy(args['strategy'], new_path, args['template'])
|
deploy_new_strategy(args["strategy"], new_path, args["template"])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ConfigurationError("`new-strategy` requires --strategy to be set.")
|
raise ConfigurationError("`new-strategy` requires --strategy to be set.")
|
||||||
|
@ -100,8 +102,8 @@ def clean_ui_subdir(directory: Path):
|
||||||
if directory.is_dir():
|
if directory.is_dir():
|
||||||
logger.info("Removing UI directory content.")
|
logger.info("Removing UI directory content.")
|
||||||
|
|
||||||
for p in reversed(list(directory.glob('**/*'))): # iterate contents from leaves to root
|
for p in reversed(list(directory.glob("**/*"))): # iterate contents from leaves to root
|
||||||
if p.name in ('.gitkeep', 'fallback_file.html'):
|
if p.name in (".gitkeep", "fallback_file.html"):
|
||||||
continue
|
continue
|
||||||
if p.is_file():
|
if p.is_file():
|
||||||
p.unlink()
|
p.unlink()
|
||||||
|
@ -110,11 +112,11 @@ def clean_ui_subdir(directory: Path):
|
||||||
|
|
||||||
|
|
||||||
def read_ui_version(dest_folder: Path) -> Optional[str]:
|
def read_ui_version(dest_folder: Path) -> Optional[str]:
|
||||||
file = dest_folder / '.uiversion'
|
file = dest_folder / ".uiversion"
|
||||||
if not file.is_file():
|
if not file.is_file():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
with file.open('r') as f:
|
with file.open("r") as f:
|
||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,12 +135,12 @@ def download_and_install_ui(dest_folder: Path, dl_url: str, version: str):
|
||||||
destfile.mkdir(exist_ok=True)
|
destfile.mkdir(exist_ok=True)
|
||||||
else:
|
else:
|
||||||
destfile.write_bytes(x.read())
|
destfile.write_bytes(x.read())
|
||||||
with (dest_folder / '.uiversion').open('w') as f:
|
with (dest_folder / ".uiversion").open("w") as f:
|
||||||
f.write(version)
|
f.write(version)
|
||||||
|
|
||||||
|
|
||||||
def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]:
|
def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]:
|
||||||
base_url = 'https://api.github.com/repos/freqtrade/frequi/'
|
base_url = "https://api.github.com/repos/freqtrade/frequi/"
|
||||||
# Get base UI Repo path
|
# Get base UI Repo path
|
||||||
|
|
||||||
resp = requests.get(f"{base_url}releases", timeout=req_timeout)
|
resp = requests.get(f"{base_url}releases", timeout=req_timeout)
|
||||||
|
@ -146,42 +148,41 @@ def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]:
|
||||||
r = resp.json()
|
r = resp.json()
|
||||||
|
|
||||||
if version:
|
if version:
|
||||||
tmp = [x for x in r if x['name'] == version]
|
tmp = [x for x in r if x["name"] == version]
|
||||||
if tmp:
|
if tmp:
|
||||||
latest_version = tmp[0]['name']
|
latest_version = tmp[0]["name"]
|
||||||
assets = tmp[0].get('assets', [])
|
assets = tmp[0].get("assets", [])
|
||||||
else:
|
else:
|
||||||
raise ValueError("UI-Version not found.")
|
raise ValueError("UI-Version not found.")
|
||||||
else:
|
else:
|
||||||
latest_version = r[0]['name']
|
latest_version = r[0]["name"]
|
||||||
assets = r[0].get('assets', [])
|
assets = r[0].get("assets", [])
|
||||||
dl_url = ''
|
dl_url = ""
|
||||||
if assets and len(assets) > 0:
|
if assets and len(assets) > 0:
|
||||||
dl_url = assets[0]['browser_download_url']
|
dl_url = assets[0]["browser_download_url"]
|
||||||
|
|
||||||
# URL not found - try assets url
|
# URL not found - try assets url
|
||||||
if not dl_url:
|
if not dl_url:
|
||||||
assets = r[0]['assets_url']
|
assets = r[0]["assets_url"]
|
||||||
resp = requests.get(assets, timeout=req_timeout)
|
resp = requests.get(assets, timeout=req_timeout)
|
||||||
r = resp.json()
|
r = resp.json()
|
||||||
dl_url = r[0]['browser_download_url']
|
dl_url = r[0]["browser_download_url"]
|
||||||
|
|
||||||
return dl_url, latest_version
|
return dl_url, latest_version
|
||||||
|
|
||||||
|
|
||||||
def start_install_ui(args: Dict[str, Any]) -> None:
|
def start_install_ui(args: Dict[str, Any]) -> None:
|
||||||
|
dest_folder = Path(__file__).parents[1] / "rpc/api_server/ui/installed/"
|
||||||
dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui/installed/'
|
|
||||||
# First make sure the assets are removed.
|
# First make sure the assets are removed.
|
||||||
dl_url, latest_version = get_ui_download_url(args.get('ui_version'))
|
dl_url, latest_version = get_ui_download_url(args.get("ui_version"))
|
||||||
|
|
||||||
curr_version = read_ui_version(dest_folder)
|
curr_version = read_ui_version(dest_folder)
|
||||||
if curr_version == latest_version and not args.get('erase_ui_only'):
|
if curr_version == latest_version and not args.get("erase_ui_only"):
|
||||||
logger.info(f"UI already up-to-date, FreqUI Version {curr_version}.")
|
logger.info(f"UI already up-to-date, FreqUI Version {curr_version}.")
|
||||||
return
|
return
|
||||||
|
|
||||||
clean_ui_subdir(dest_folder)
|
clean_ui_subdir(dest_folder)
|
||||||
if args.get('erase_ui_only'):
|
if args.get("erase_ui_only"):
|
||||||
logger.info("Erased UI directory content. Not downloading new version.")
|
logger.info("Erased UI directory content. Not downloading new version.")
|
||||||
else:
|
else:
|
||||||
# Download a new version
|
# Download a new version
|
||||||
|
|
|
@ -22,15 +22,15 @@ def start_hyperopt_list(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
|
|
||||||
print_colorized = config.get('print_colorized', False)
|
print_colorized = config.get("print_colorized", False)
|
||||||
print_json = config.get('print_json', False)
|
print_json = config.get("print_json", False)
|
||||||
export_csv = config.get('export_csv')
|
export_csv = config.get("export_csv")
|
||||||
no_details = config.get('hyperopt_list_no_details', False)
|
no_details = config.get("hyperopt_list_no_details", False)
|
||||||
no_header = False
|
no_header = False
|
||||||
|
|
||||||
results_file = get_latest_hyperopt_file(
|
results_file = get_latest_hyperopt_file(
|
||||||
config['user_data_dir'] / 'hyperopt_results',
|
config["user_data_dir"] / "hyperopt_results", config.get("hyperoptexportfilename")
|
||||||
config.get('hyperoptexportfilename'))
|
)
|
||||||
|
|
||||||
# Previous evaluations
|
# Previous evaluations
|
||||||
epochs, total_epochs = HyperoptTools.load_filtered_results(results_file, config)
|
epochs, total_epochs = HyperoptTools.load_filtered_results(results_file, config)
|
||||||
|
@ -40,21 +40,26 @@ def start_hyperopt_list(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
if not export_csv:
|
if not export_csv:
|
||||||
try:
|
try:
|
||||||
print(HyperoptTools.get_result_table(config, epochs, total_epochs,
|
print(
|
||||||
not config.get('hyperopt_list_best', False),
|
HyperoptTools.get_result_table(
|
||||||
print_colorized, 0))
|
config,
|
||||||
|
epochs,
|
||||||
|
total_epochs,
|
||||||
|
not config.get("hyperopt_list_best", False),
|
||||||
|
print_colorized,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print('User interrupted..')
|
print("User interrupted..")
|
||||||
|
|
||||||
if epochs and not no_details:
|
if epochs and not no_details:
|
||||||
sorted_epochs = sorted(epochs, key=itemgetter('loss'))
|
sorted_epochs = sorted(epochs, key=itemgetter("loss"))
|
||||||
results = sorted_epochs[0]
|
results = sorted_epochs[0]
|
||||||
HyperoptTools.show_epoch_details(results, total_epochs, print_json, no_header)
|
HyperoptTools.show_epoch_details(results, total_epochs, print_json, no_header)
|
||||||
|
|
||||||
if epochs and export_csv:
|
if epochs and export_csv:
|
||||||
HyperoptTools.export_csv_file(
|
HyperoptTools.export_csv_file(config, epochs, export_csv)
|
||||||
config, epochs, export_csv
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def start_hyperopt_show(args: Dict[str, Any]) -> None:
|
def start_hyperopt_show(args: Dict[str, Any]) -> None:
|
||||||
|
@ -65,13 +70,13 @@ def start_hyperopt_show(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
|
|
||||||
print_json = config.get('print_json', False)
|
print_json = config.get("print_json", False)
|
||||||
no_header = config.get('hyperopt_show_no_header', False)
|
no_header = config.get("hyperopt_show_no_header", False)
|
||||||
results_file = get_latest_hyperopt_file(
|
results_file = get_latest_hyperopt_file(
|
||||||
config['user_data_dir'] / 'hyperopt_results',
|
config["user_data_dir"] / "hyperopt_results", config.get("hyperoptexportfilename")
|
||||||
config.get('hyperoptexportfilename'))
|
)
|
||||||
|
|
||||||
n = config.get('hyperopt_show_index', -1)
|
n = config.get("hyperopt_show_index", -1)
|
||||||
|
|
||||||
# Previous evaluations
|
# Previous evaluations
|
||||||
epochs, total_epochs = HyperoptTools.load_filtered_results(results_file, config)
|
epochs, total_epochs = HyperoptTools.load_filtered_results(results_file, config)
|
||||||
|
@ -80,10 +85,12 @@ def start_hyperopt_show(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
if n > filtered_epochs:
|
if n > filtered_epochs:
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f"The index of the epoch to show should be less than {filtered_epochs + 1}.")
|
f"The index of the epoch to show should be less than {filtered_epochs + 1}."
|
||||||
|
)
|
||||||
if n < -filtered_epochs:
|
if n < -filtered_epochs:
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f"The index of the epoch to show should be greater than {-filtered_epochs - 1}.")
|
f"The index of the epoch to show should be greater than {-filtered_epochs - 1}."
|
||||||
|
)
|
||||||
|
|
||||||
# Translate epoch index from human-readable format to pythonic
|
# Translate epoch index from human-readable format to pythonic
|
||||||
if n > 0:
|
if n > 0:
|
||||||
|
@ -92,13 +99,18 @@ def start_hyperopt_show(args: Dict[str, Any]) -> None:
|
||||||
if epochs:
|
if epochs:
|
||||||
val = epochs[n]
|
val = epochs[n]
|
||||||
|
|
||||||
metrics = val['results_metrics']
|
metrics = val["results_metrics"]
|
||||||
if 'strategy_name' in metrics:
|
if "strategy_name" in metrics:
|
||||||
strategy_name = metrics['strategy_name']
|
strategy_name = metrics["strategy_name"]
|
||||||
show_backtest_result(strategy_name, metrics,
|
show_backtest_result(
|
||||||
metrics['stake_currency'], config.get('backtest_breakdown', []))
|
strategy_name,
|
||||||
|
metrics,
|
||||||
|
metrics["stake_currency"],
|
||||||
|
config.get("backtest_breakdown", []),
|
||||||
|
)
|
||||||
|
|
||||||
HyperoptTools.try_export_params(config, strategy_name, val)
|
HyperoptTools.try_export_params(config, strategy_name, val)
|
||||||
|
|
||||||
HyperoptTools.show_epoch_details(val, total_epochs, print_json, no_header,
|
HyperoptTools.show_epoch_details(
|
||||||
header_str="Epoch details")
|
val, total_epochs, print_json, no_header, header_str="Epoch details"
|
||||||
|
)
|
||||||
|
|
|
@ -26,42 +26,47 @@ def start_list_exchanges(args: Dict[str, Any]) -> None:
|
||||||
:param args: Cli args from Arguments()
|
:param args: Cli args from Arguments()
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
exchanges = list_available_exchanges(args['list_exchanges_all'])
|
exchanges = list_available_exchanges(args["list_exchanges_all"])
|
||||||
|
|
||||||
if args['print_one_column']:
|
if args["print_one_column"]:
|
||||||
print('\n'.join([e['name'] for e in exchanges]))
|
print("\n".join([e["name"] for e in exchanges]))
|
||||||
else:
|
else:
|
||||||
headers = {
|
headers = {
|
||||||
'name': 'Exchange name',
|
"name": "Exchange name",
|
||||||
'supported': 'Supported',
|
"supported": "Supported",
|
||||||
'trade_modes': 'Markets',
|
"trade_modes": "Markets",
|
||||||
'comment': 'Reason',
|
"comment": "Reason",
|
||||||
}
|
}
|
||||||
headers.update({'valid': 'Valid'} if args['list_exchanges_all'] else {})
|
headers.update({"valid": "Valid"} if args["list_exchanges_all"] else {})
|
||||||
|
|
||||||
def build_entry(exchange: ValidExchangesType, valid: bool):
|
def build_entry(exchange: ValidExchangesType, valid: bool):
|
||||||
valid_entry = {'valid': exchange['valid']} if valid else {}
|
valid_entry = {"valid": exchange["valid"]} if valid else {}
|
||||||
result: Dict[str, Union[str, bool]] = {
|
result: Dict[str, Union[str, bool]] = {
|
||||||
'name': exchange['name'],
|
"name": exchange["name"],
|
||||||
**valid_entry,
|
**valid_entry,
|
||||||
'supported': 'Official' if exchange['supported'] else '',
|
"supported": "Official" if exchange["supported"] else "",
|
||||||
'trade_modes': ', '.join(
|
"trade_modes": ", ".join(
|
||||||
(f"{a['margin_mode']} " if a['margin_mode'] else '') + a['trading_mode']
|
(f"{a['margin_mode']} " if a["margin_mode"] else "") + a["trading_mode"]
|
||||||
for a in exchange['trade_modes']
|
for a in exchange["trade_modes"]
|
||||||
),
|
),
|
||||||
'comment': exchange['comment'],
|
"comment": exchange["comment"],
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
if args['list_exchanges_all']:
|
if args["list_exchanges_all"]:
|
||||||
print("All exchanges supported by the ccxt library:")
|
print("All exchanges supported by the ccxt library:")
|
||||||
exchanges = [build_entry(e, True) for e in exchanges]
|
exchanges = [build_entry(e, True) for e in exchanges]
|
||||||
else:
|
else:
|
||||||
print("Exchanges available for Freqtrade:")
|
print("Exchanges available for Freqtrade:")
|
||||||
exchanges = [build_entry(e, False) for e in exchanges if e['valid'] is not False]
|
exchanges = [build_entry(e, False) for e in exchanges if e["valid"] is not False]
|
||||||
|
|
||||||
print(tabulate(exchanges, headers=headers, ))
|
print(
|
||||||
|
tabulate(
|
||||||
|
exchanges,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _print_objs_tabular(objs: List, print_colorized: bool) -> None:
|
def _print_objs_tabular(objs: List, print_colorized: bool) -> None:
|
||||||
|
@ -71,26 +76,35 @@ def _print_objs_tabular(objs: List, print_colorized: bool) -> None:
|
||||||
yellow = Fore.YELLOW
|
yellow = Fore.YELLOW
|
||||||
reset = Style.RESET_ALL
|
reset = Style.RESET_ALL
|
||||||
else:
|
else:
|
||||||
red = ''
|
red = ""
|
||||||
yellow = ''
|
yellow = ""
|
||||||
reset = ''
|
reset = ""
|
||||||
|
|
||||||
names = [s['name'] for s in objs]
|
names = [s["name"] for s in objs]
|
||||||
objs_to_print = [{
|
objs_to_print = [
|
||||||
'name': s['name'] if s['name'] else "--",
|
{
|
||||||
'location': s['location_rel'],
|
"name": s["name"] if s["name"] else "--",
|
||||||
'status': (red + "LOAD FAILED" + reset if s['class'] is None
|
"location": s["location_rel"],
|
||||||
else "OK" if names.count(s['name']) == 1
|
"status": (
|
||||||
else yellow + "DUPLICATE NAME" + reset)
|
red + "LOAD FAILED" + reset
|
||||||
} for s in objs]
|
if s["class"] is None
|
||||||
|
else "OK"
|
||||||
|
if names.count(s["name"]) == 1
|
||||||
|
else yellow + "DUPLICATE NAME" + reset
|
||||||
|
),
|
||||||
|
}
|
||||||
|
for s in objs
|
||||||
|
]
|
||||||
for idx, s in enumerate(objs):
|
for idx, s in enumerate(objs):
|
||||||
if 'hyperoptable' in s:
|
if "hyperoptable" in s:
|
||||||
objs_to_print[idx].update({
|
objs_to_print[idx].update(
|
||||||
'hyperoptable': "Yes" if s['hyperoptable']['count'] > 0 else "No",
|
{
|
||||||
'buy-Params': len(s['hyperoptable'].get('buy', [])),
|
"hyperoptable": "Yes" if s["hyperoptable"]["count"] > 0 else "No",
|
||||||
'sell-Params': len(s['hyperoptable'].get('sell', [])),
|
"buy-Params": len(s["hyperoptable"].get("buy", [])),
|
||||||
})
|
"sell-Params": len(s["hyperoptable"].get("sell", [])),
|
||||||
print(tabulate(objs_to_print, headers='keys', tablefmt='psql', stralign='right'))
|
}
|
||||||
|
)
|
||||||
|
print(tabulate(objs_to_print, headers="keys", tablefmt="psql", stralign="right"))
|
||||||
|
|
||||||
|
|
||||||
def start_list_strategies(args: Dict[str, Any]) -> None:
|
def start_list_strategies(args: Dict[str, Any]) -> None:
|
||||||
|
@ -100,19 +114,20 @@ def start_list_strategies(args: Dict[str, Any]) -> None:
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
|
|
||||||
strategy_objs = StrategyResolver.search_all_objects(
|
strategy_objs = StrategyResolver.search_all_objects(
|
||||||
config, not args['print_one_column'], config.get('recursive_strategy_search', False))
|
config, not args["print_one_column"], config.get("recursive_strategy_search", False)
|
||||||
|
)
|
||||||
# Sort alphabetically
|
# Sort alphabetically
|
||||||
strategy_objs = sorted(strategy_objs, key=lambda x: x['name'])
|
strategy_objs = sorted(strategy_objs, key=lambda x: x["name"])
|
||||||
for obj in strategy_objs:
|
for obj in strategy_objs:
|
||||||
if obj['class']:
|
if obj["class"]:
|
||||||
obj['hyperoptable'] = obj['class'].detect_all_parameters()
|
obj["hyperoptable"] = obj["class"].detect_all_parameters()
|
||||||
else:
|
else:
|
||||||
obj['hyperoptable'] = {'count': 0}
|
obj["hyperoptable"] = {"count": 0}
|
||||||
|
|
||||||
if args['print_one_column']:
|
if args["print_one_column"]:
|
||||||
print('\n'.join([s['name'] for s in strategy_objs]))
|
print("\n".join([s["name"] for s in strategy_objs]))
|
||||||
else:
|
else:
|
||||||
_print_objs_tabular(strategy_objs, config.get('print_colorized', False))
|
_print_objs_tabular(strategy_objs, config.get("print_colorized", False))
|
||||||
|
|
||||||
|
|
||||||
def start_list_freqAI_models(args: Dict[str, Any]) -> None:
|
def start_list_freqAI_models(args: Dict[str, Any]) -> None:
|
||||||
|
@ -121,13 +136,14 @@ def start_list_freqAI_models(args: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver
|
from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver
|
||||||
model_objs = FreqaiModelResolver.search_all_objects(config, not args['print_one_column'])
|
|
||||||
|
model_objs = FreqaiModelResolver.search_all_objects(config, not args["print_one_column"])
|
||||||
# Sort alphabetically
|
# Sort alphabetically
|
||||||
model_objs = sorted(model_objs, key=lambda x: x['name'])
|
model_objs = sorted(model_objs, key=lambda x: x["name"])
|
||||||
if args['print_one_column']:
|
if args["print_one_column"]:
|
||||||
print('\n'.join([s['name'] for s in model_objs]))
|
print("\n".join([s["name"] for s in model_objs]))
|
||||||
else:
|
else:
|
||||||
_print_objs_tabular(model_objs, config.get('print_colorized', False))
|
_print_objs_tabular(model_objs, config.get("print_colorized", False))
|
||||||
|
|
||||||
|
|
||||||
def start_list_timeframes(args: Dict[str, Any]) -> None:
|
def start_list_timeframes(args: Dict[str, Any]) -> None:
|
||||||
|
@ -136,16 +152,18 @@ def start_list_timeframes(args: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
||||||
# Do not use timeframe set in the config
|
# Do not use timeframe set in the config
|
||||||
config['timeframe'] = None
|
config["timeframe"] = None
|
||||||
|
|
||||||
# Init exchange
|
# Init exchange
|
||||||
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
||||||
|
|
||||||
if args['print_one_column']:
|
if args["print_one_column"]:
|
||||||
print('\n'.join(exchange.timeframes))
|
print("\n".join(exchange.timeframes))
|
||||||
else:
|
else:
|
||||||
print(f"Timeframes available for the exchange `{exchange.name}`: "
|
print(
|
||||||
f"{', '.join(exchange.timeframes)}")
|
f"Timeframes available for the exchange `{exchange.name}`: "
|
||||||
|
f"{', '.join(exchange.timeframes)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None:
|
def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None:
|
||||||
|
@ -161,51 +179,75 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None:
|
||||||
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
||||||
|
|
||||||
# By default only active pairs/markets are to be shown
|
# By default only active pairs/markets are to be shown
|
||||||
active_only = not args.get('list_pairs_all', False)
|
active_only = not args.get("list_pairs_all", False)
|
||||||
|
|
||||||
base_currencies = args.get('base_currencies', [])
|
base_currencies = args.get("base_currencies", [])
|
||||||
quote_currencies = args.get('quote_currencies', [])
|
quote_currencies = args.get("quote_currencies", [])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pairs = exchange.get_markets(base_currencies=base_currencies,
|
pairs = exchange.get_markets(
|
||||||
quote_currencies=quote_currencies,
|
base_currencies=base_currencies,
|
||||||
tradable_only=pairs_only,
|
quote_currencies=quote_currencies,
|
||||||
active_only=active_only)
|
tradable_only=pairs_only,
|
||||||
|
active_only=active_only,
|
||||||
|
)
|
||||||
# Sort the pairs/markets by symbol
|
# Sort the pairs/markets by symbol
|
||||||
pairs = dict(sorted(pairs.items()))
|
pairs = dict(sorted(pairs.items()))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise OperationalException(f"Cannot get markets. Reason: {e}") from e
|
raise OperationalException(f"Cannot get markets. Reason: {e}") from e
|
||||||
|
|
||||||
else:
|
else:
|
||||||
summary_str = ((f"Exchange {exchange.name} has {len(pairs)} ") +
|
summary_str = (
|
||||||
("active " if active_only else "") +
|
(f"Exchange {exchange.name} has {len(pairs)} ")
|
||||||
(plural(len(pairs), "pair" if pairs_only else "market")) +
|
+ ("active " if active_only else "")
|
||||||
(f" with {', '.join(base_currencies)} as base "
|
+ (plural(len(pairs), "pair" if pairs_only else "market"))
|
||||||
f"{plural(len(base_currencies), 'currency', 'currencies')}"
|
+ (
|
||||||
if base_currencies else "") +
|
f" with {', '.join(base_currencies)} as base "
|
||||||
(" and" if base_currencies and quote_currencies else "") +
|
f"{plural(len(base_currencies), 'currency', 'currencies')}"
|
||||||
(f" with {', '.join(quote_currencies)} as quote "
|
if base_currencies
|
||||||
f"{plural(len(quote_currencies), 'currency', 'currencies')}"
|
else ""
|
||||||
if quote_currencies else ""))
|
)
|
||||||
|
+ (" and" if base_currencies and quote_currencies else "")
|
||||||
|
+ (
|
||||||
|
f" with {', '.join(quote_currencies)} as quote "
|
||||||
|
f"{plural(len(quote_currencies), 'currency', 'currencies')}"
|
||||||
|
if quote_currencies
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
headers = ["Id", "Symbol", "Base", "Quote", "Active",
|
headers = [
|
||||||
"Spot", "Margin", "Future", "Leverage"]
|
"Id",
|
||||||
|
"Symbol",
|
||||||
|
"Base",
|
||||||
|
"Quote",
|
||||||
|
"Active",
|
||||||
|
"Spot",
|
||||||
|
"Margin",
|
||||||
|
"Future",
|
||||||
|
"Leverage",
|
||||||
|
]
|
||||||
|
|
||||||
tabular_data = [{
|
tabular_data = [
|
||||||
'Id': v['id'],
|
{
|
||||||
'Symbol': v['symbol'],
|
"Id": v["id"],
|
||||||
'Base': v['base'],
|
"Symbol": v["symbol"],
|
||||||
'Quote': v['quote'],
|
"Base": v["base"],
|
||||||
'Active': market_is_active(v),
|
"Quote": v["quote"],
|
||||||
'Spot': 'Spot' if exchange.market_is_spot(v) else '',
|
"Active": market_is_active(v),
|
||||||
'Margin': 'Margin' if exchange.market_is_margin(v) else '',
|
"Spot": "Spot" if exchange.market_is_spot(v) else "",
|
||||||
'Future': 'Future' if exchange.market_is_future(v) else '',
|
"Margin": "Margin" if exchange.market_is_margin(v) else "",
|
||||||
'Leverage': exchange.get_max_leverage(v['symbol'], 20)
|
"Future": "Future" if exchange.market_is_future(v) else "",
|
||||||
} for _, v in pairs.items()]
|
"Leverage": exchange.get_max_leverage(v["symbol"], 20),
|
||||||
|
}
|
||||||
|
for _, v in pairs.items()
|
||||||
|
]
|
||||||
|
|
||||||
if (args.get('print_one_column', False) or
|
if (
|
||||||
args.get('list_pairs_print_json', False) or
|
args.get("print_one_column", False)
|
||||||
args.get('print_csv', False)):
|
or args.get("list_pairs_print_json", False)
|
||||||
|
or args.get("print_csv", False)
|
||||||
|
):
|
||||||
# Print summary string in the log in case of machine-readable
|
# Print summary string in the log in case of machine-readable
|
||||||
# regular formats.
|
# regular formats.
|
||||||
logger.info(f"{summary_str}.")
|
logger.info(f"{summary_str}.")
|
||||||
|
@ -215,24 +257,26 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None:
|
||||||
print()
|
print()
|
||||||
|
|
||||||
if pairs:
|
if pairs:
|
||||||
if args.get('print_list', False):
|
if args.get("print_list", False):
|
||||||
# print data as a list, with human-readable summary
|
# print data as a list, with human-readable summary
|
||||||
print(f"{summary_str}: {', '.join(pairs.keys())}.")
|
print(f"{summary_str}: {', '.join(pairs.keys())}.")
|
||||||
elif args.get('print_one_column', False):
|
elif args.get("print_one_column", False):
|
||||||
print('\n'.join(pairs.keys()))
|
print("\n".join(pairs.keys()))
|
||||||
elif args.get('list_pairs_print_json', False):
|
elif args.get("list_pairs_print_json", False):
|
||||||
print(rapidjson.dumps(list(pairs.keys()), default=str))
|
print(rapidjson.dumps(list(pairs.keys()), default=str))
|
||||||
elif args.get('print_csv', False):
|
elif args.get("print_csv", False):
|
||||||
writer = csv.DictWriter(sys.stdout, fieldnames=headers)
|
writer = csv.DictWriter(sys.stdout, fieldnames=headers)
|
||||||
writer.writeheader()
|
writer.writeheader()
|
||||||
writer.writerows(tabular_data)
|
writer.writerows(tabular_data)
|
||||||
else:
|
else:
|
||||||
# print data as a table, with the human-readable summary
|
# print data as a table, with the human-readable summary
|
||||||
print(f"{summary_str}:")
|
print(f"{summary_str}:")
|
||||||
print(tabulate(tabular_data, headers='keys', tablefmt='psql', stralign='right'))
|
print(tabulate(tabular_data, headers="keys", tablefmt="psql", stralign="right"))
|
||||||
elif not (args.get('print_one_column', False) or
|
elif not (
|
||||||
args.get('list_pairs_print_json', False) or
|
args.get("print_one_column", False)
|
||||||
args.get('print_csv', False)):
|
or args.get("list_pairs_print_json", False)
|
||||||
|
or args.get("print_csv", False)
|
||||||
|
):
|
||||||
print(f"{summary_str}.")
|
print(f"{summary_str}.")
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,21 +287,22 @@ def start_show_trades(args: Dict[str, Any]) -> None:
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from freqtrade.persistence import Trade, init_db
|
from freqtrade.persistence import Trade, init_db
|
||||||
|
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
|
|
||||||
if 'db_url' not in config:
|
if "db_url" not in config:
|
||||||
raise ConfigurationError("--db-url is required for this command.")
|
raise ConfigurationError("--db-url is required for this command.")
|
||||||
|
|
||||||
logger.info(f'Using DB: "{parse_db_uri_for_logging(config["db_url"])}"')
|
logger.info(f'Using DB: "{parse_db_uri_for_logging(config["db_url"])}"')
|
||||||
init_db(config['db_url'])
|
init_db(config["db_url"])
|
||||||
tfilter = []
|
tfilter = []
|
||||||
|
|
||||||
if config.get('trade_ids'):
|
if config.get("trade_ids"):
|
||||||
tfilter.append(Trade.id.in_(config['trade_ids']))
|
tfilter.append(Trade.id.in_(config["trade_ids"]))
|
||||||
|
|
||||||
trades = Trade.get_trades(tfilter).all()
|
trades = Trade.get_trades(tfilter).all()
|
||||||
logger.info(f"Printing {len(trades)} Trades: ")
|
logger.info(f"Printing {len(trades)} Trades: ")
|
||||||
if config.get('print_json', False):
|
if config.get("print_json", False):
|
||||||
print(json.dumps([trade.to_json() for trade in trades], indent=4))
|
print(json.dumps([trade.to_json() for trade in trades], indent=4))
|
||||||
else:
|
else:
|
||||||
for trade in trades:
|
for trade in trades:
|
||||||
|
|
|
@ -21,20 +21,22 @@ def setup_optimize_configuration(args: Dict[str, Any], method: RunMode) -> Dict[
|
||||||
config = setup_utils_configuration(args, method)
|
config = setup_utils_configuration(args, method)
|
||||||
|
|
||||||
no_unlimited_runmodes = {
|
no_unlimited_runmodes = {
|
||||||
RunMode.BACKTEST: 'backtesting',
|
RunMode.BACKTEST: "backtesting",
|
||||||
RunMode.HYPEROPT: 'hyperoptimization',
|
RunMode.HYPEROPT: "hyperoptimization",
|
||||||
}
|
}
|
||||||
if method in no_unlimited_runmodes.keys():
|
if method in no_unlimited_runmodes.keys():
|
||||||
wallet_size = config['dry_run_wallet'] * config['tradable_balance_ratio']
|
wallet_size = config["dry_run_wallet"] * config["tradable_balance_ratio"]
|
||||||
# tradable_balance_ratio
|
# tradable_balance_ratio
|
||||||
if (config['stake_amount'] != constants.UNLIMITED_STAKE_AMOUNT
|
if (
|
||||||
and config['stake_amount'] > wallet_size):
|
config["stake_amount"] != constants.UNLIMITED_STAKE_AMOUNT
|
||||||
wallet = fmt_coin(wallet_size, config['stake_currency'])
|
and config["stake_amount"] > wallet_size
|
||||||
stake = fmt_coin(config['stake_amount'], config['stake_currency'])
|
):
|
||||||
|
wallet = fmt_coin(wallet_size, config["stake_currency"])
|
||||||
|
stake = fmt_coin(config["stake_amount"], config["stake_currency"])
|
||||||
raise ConfigurationError(
|
raise ConfigurationError(
|
||||||
f"Starting balance ({wallet}) is smaller than stake_amount {stake}. "
|
f"Starting balance ({wallet}) is smaller than stake_amount {stake}. "
|
||||||
f"Wallet is calculated as `dry_run_wallet * tradable_balance_ratio`."
|
f"Wallet is calculated as `dry_run_wallet * tradable_balance_ratio`."
|
||||||
)
|
)
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
@ -51,7 +53,7 @@ def start_backtesting(args: Dict[str, Any]) -> None:
|
||||||
# Initialize configuration
|
# Initialize configuration
|
||||||
config = setup_optimize_configuration(args, RunMode.BACKTEST)
|
config = setup_optimize_configuration(args, RunMode.BACKTEST)
|
||||||
|
|
||||||
logger.info('Starting freqtrade in Backtesting mode')
|
logger.info("Starting freqtrade in Backtesting mode")
|
||||||
|
|
||||||
# Initialize backtesting object
|
# Initialize backtesting object
|
||||||
backtesting = Backtesting(config)
|
backtesting = Backtesting(config)
|
||||||
|
@ -68,7 +70,7 @@ def start_backtesting_show(args: Dict[str, Any]) -> None:
|
||||||
from freqtrade.data.btanalysis import load_backtest_stats
|
from freqtrade.data.btanalysis import load_backtest_stats
|
||||||
from freqtrade.optimize.optimize_reports import show_backtest_results, show_sorted_pairlist
|
from freqtrade.optimize.optimize_reports import show_backtest_results, show_sorted_pairlist
|
||||||
|
|
||||||
results = load_backtest_stats(config['exportfilename'])
|
results = load_backtest_stats(config["exportfilename"])
|
||||||
|
|
||||||
show_backtest_results(config, results)
|
show_backtest_results(config, results)
|
||||||
show_sorted_pairlist(config, results)
|
show_sorted_pairlist(config, results)
|
||||||
|
@ -87,20 +89,20 @@ def start_hyperopt(args: Dict[str, Any]) -> None:
|
||||||
from freqtrade.optimize.hyperopt import Hyperopt
|
from freqtrade.optimize.hyperopt import Hyperopt
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f"{e}. Please ensure that the hyperopt dependencies are installed.") from e
|
f"{e}. Please ensure that the hyperopt dependencies are installed."
|
||||||
|
) from e
|
||||||
# Initialize configuration
|
# Initialize configuration
|
||||||
config = setup_optimize_configuration(args, RunMode.HYPEROPT)
|
config = setup_optimize_configuration(args, RunMode.HYPEROPT)
|
||||||
|
|
||||||
logger.info('Starting freqtrade in Hyperopt mode')
|
logger.info("Starting freqtrade in Hyperopt mode")
|
||||||
|
|
||||||
lock = FileLock(Hyperopt.get_lock_filename(config))
|
lock = FileLock(Hyperopt.get_lock_filename(config))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with lock.acquire(timeout=1):
|
with lock.acquire(timeout=1):
|
||||||
|
|
||||||
# Remove noisy log messages
|
# Remove noisy log messages
|
||||||
logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING)
|
logging.getLogger("hyperopt.tpe").setLevel(logging.WARNING)
|
||||||
logging.getLogger('filelock').setLevel(logging.WARNING)
|
logging.getLogger("filelock").setLevel(logging.WARNING)
|
||||||
|
|
||||||
# Initialize backtesting object
|
# Initialize backtesting object
|
||||||
hyperopt = Hyperopt(config)
|
hyperopt = Hyperopt(config)
|
||||||
|
@ -108,9 +110,11 @@ def start_hyperopt(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
except Timeout:
|
except Timeout:
|
||||||
logger.info("Another running instance of freqtrade Hyperopt detected.")
|
logger.info("Another running instance of freqtrade Hyperopt detected.")
|
||||||
logger.info("Simultaneous execution of multiple Hyperopt commands is not supported. "
|
logger.info(
|
||||||
"Hyperopt module is resource hungry. Please run your Hyperopt sequentially "
|
"Simultaneous execution of multiple Hyperopt commands is not supported. "
|
||||||
"or on separate machines.")
|
"Hyperopt module is resource hungry. Please run your Hyperopt sequentially "
|
||||||
|
"or on separate machines."
|
||||||
|
)
|
||||||
logger.info("Quitting now.")
|
logger.info("Quitting now.")
|
||||||
# TODO: return False here in order to help freqtrade to exit
|
# TODO: return False here in order to help freqtrade to exit
|
||||||
# with non-zero exit code...
|
# with non-zero exit code...
|
||||||
|
@ -127,7 +131,7 @@ def start_edge(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
# Initialize configuration
|
# Initialize configuration
|
||||||
config = setup_optimize_configuration(args, RunMode.EDGE)
|
config = setup_optimize_configuration(args, RunMode.EDGE)
|
||||||
logger.info('Starting freqtrade in Edge mode')
|
logger.info("Starting freqtrade in Edge mode")
|
||||||
|
|
||||||
# Initialize Edge object
|
# Initialize Edge object
|
||||||
edge_cli = EdgeCli(config)
|
edge_cli = EdgeCli(config)
|
||||||
|
|
|
@ -17,28 +17,29 @@ def start_test_pairlist(args: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
from freqtrade.persistence import FtNoDBContext
|
from freqtrade.persistence import FtNoDBContext
|
||||||
from freqtrade.plugins.pairlistmanager import PairListManager
|
from freqtrade.plugins.pairlistmanager import PairListManager
|
||||||
|
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
||||||
|
|
||||||
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
||||||
|
|
||||||
quote_currencies = args.get('quote_currencies')
|
quote_currencies = args.get("quote_currencies")
|
||||||
if not quote_currencies:
|
if not quote_currencies:
|
||||||
quote_currencies = [config.get('stake_currency')]
|
quote_currencies = [config.get("stake_currency")]
|
||||||
results = {}
|
results = {}
|
||||||
with FtNoDBContext():
|
with FtNoDBContext():
|
||||||
for curr in quote_currencies:
|
for curr in quote_currencies:
|
||||||
config['stake_currency'] = curr
|
config["stake_currency"] = curr
|
||||||
pairlists = PairListManager(exchange, config)
|
pairlists = PairListManager(exchange, config)
|
||||||
pairlists.refresh_pairlist()
|
pairlists.refresh_pairlist()
|
||||||
results[curr] = pairlists.whitelist
|
results[curr] = pairlists.whitelist
|
||||||
|
|
||||||
for curr, pairlist in results.items():
|
for curr, pairlist in results.items():
|
||||||
if not args.get('print_one_column', False) and not args.get('list_pairs_print_json', False):
|
if not args.get("print_one_column", False) and not args.get("list_pairs_print_json", False):
|
||||||
print(f"Pairs for {curr}: ")
|
print(f"Pairs for {curr}: ")
|
||||||
|
|
||||||
if args.get('print_one_column', False):
|
if args.get("print_one_column", False):
|
||||||
print('\n'.join(pairlist))
|
print("\n".join(pairlist))
|
||||||
elif args.get('list_pairs_print_json', False):
|
elif args.get("list_pairs_print_json", False):
|
||||||
print(rapidjson.dumps(list(pairlist), default=str))
|
print(rapidjson.dumps(list(pairlist), default=str))
|
||||||
else:
|
else:
|
||||||
print(pairlist)
|
print(pairlist)
|
||||||
|
|
|
@ -6,10 +6,11 @@ from freqtrade.exceptions import ConfigurationError
|
||||||
|
|
||||||
|
|
||||||
def validate_plot_args(args: Dict[str, Any]) -> None:
|
def validate_plot_args(args: Dict[str, Any]) -> None:
|
||||||
if not args.get('datadir') and not args.get('config'):
|
if not args.get("datadir") and not args.get("config"):
|
||||||
raise ConfigurationError(
|
raise ConfigurationError(
|
||||||
"You need to specify either `--datadir` or `--config` "
|
"You need to specify either `--datadir` or `--config` "
|
||||||
"for plot-profit and plot-dataframe.")
|
"for plot-profit and plot-dataframe."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def start_plot_dataframe(args: Dict[str, Any]) -> None:
|
def start_plot_dataframe(args: Dict[str, Any]) -> None:
|
||||||
|
@ -18,6 +19,7 @@ def start_plot_dataframe(args: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
# Import here to avoid errors if plot-dependencies are not installed.
|
# Import here to avoid errors if plot-dependencies are not installed.
|
||||||
from freqtrade.plot.plotting import load_and_plot_trades
|
from freqtrade.plot.plotting import load_and_plot_trades
|
||||||
|
|
||||||
validate_plot_args(args)
|
validate_plot_args(args)
|
||||||
config = setup_utils_configuration(args, RunMode.PLOT)
|
config = setup_utils_configuration(args, RunMode.PLOT)
|
||||||
|
|
||||||
|
@ -30,6 +32,7 @@ def start_plot_profit(args: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
# Import here to avoid errors if plot-dependencies are not installed.
|
# Import here to avoid errors if plot-dependencies are not installed.
|
||||||
from freqtrade.plot.plotting import plot_profit
|
from freqtrade.plot.plotting import plot_profit
|
||||||
|
|
||||||
validate_plot_args(args)
|
validate_plot_args(args)
|
||||||
config = setup_utils_configuration(args, RunMode.PLOT)
|
config = setup_utils_configuration(args, RunMode.PLOT)
|
||||||
|
|
||||||
|
|
|
@ -26,13 +26,15 @@ def start_strategy_update(args: Dict[str, Any]) -> None:
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
|
|
||||||
strategy_objs = StrategyResolver.search_all_objects(
|
strategy_objs = StrategyResolver.search_all_objects(
|
||||||
config, enum_failed=False, recursive=config.get('recursive_strategy_search', False))
|
config, enum_failed=False, recursive=config.get("recursive_strategy_search", False)
|
||||||
|
)
|
||||||
|
|
||||||
filtered_strategy_objs = []
|
filtered_strategy_objs = []
|
||||||
if args['strategy_list']:
|
if args["strategy_list"]:
|
||||||
filtered_strategy_objs = [
|
filtered_strategy_objs = [
|
||||||
strategy_obj for strategy_obj in strategy_objs
|
strategy_obj
|
||||||
if strategy_obj['name'] in args['strategy_list']
|
for strategy_obj in strategy_objs
|
||||||
|
if strategy_obj["name"] in args["strategy_list"]
|
||||||
]
|
]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -41,8 +43,8 @@ def start_strategy_update(args: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
processed_locations = set()
|
processed_locations = set()
|
||||||
for strategy_obj in filtered_strategy_objs:
|
for strategy_obj in filtered_strategy_objs:
|
||||||
if strategy_obj['location'] not in processed_locations:
|
if strategy_obj["location"] not in processed_locations:
|
||||||
processed_locations.add(strategy_obj['location'])
|
processed_locations.add(strategy_obj["location"])
|
||||||
start_conversion(strategy_obj, config)
|
start_conversion(strategy_obj, config)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user