stable/freqtrade/configuration/arguments.py

183 lines
7.1 KiB
Python
Raw Normal View History

"""
This module contains the argument manager class
"""
import argparse
import re
2018-07-04 07:31:35 +00:00
from typing import List, NamedTuple, Optional
import arrow
2019-07-25 23:21:31 +00:00
from freqtrade.configuration.cli_options import AVAILABLE_CLI_OPTIONS
from freqtrade import constants
2019-07-06 22:20:26 +00:00
2019-07-21 12:32:29 +00:00
ARGS_COMMON = ["verbosity", "logfile", "version", "config", "datadir", "user_data_dir"]
2019-07-06 22:20:26 +00:00
ARGS_STRATEGY = ["strategy", "strategy_path"]
ARGS_MAIN = ARGS_COMMON + ARGS_STRATEGY + ["db_url", "sd_notify"]
2019-07-06 21:51:01 +00:00
ARGS_COMMON_OPTIMIZE = ["ticker_interval", "timerange",
"max_open_trades", "stake_amount", "refresh_pairs"]
ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions",
"live", "strategy_list", "export", "exportfilename"]
2019-07-22 16:37:34 +00:00
ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path",
"position_stacking", "epochs", "spaces",
"use_max_market_positions", "print_all", "hyperopt_jobs",
"hyperopt_random_state", "hyperopt_min_trades",
2019-07-16 04:27:23 +00:00
"hyperopt_continue", "hyperopt_loss"]
ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"]
2019-07-06 21:48:39 +00:00
ARGS_LIST_EXCHANGES = ["print_one_column"]
ARGS_CREATE_USERDIR = ["user_data_dir"]
2019-06-22 18:21:42 +00:00
ARGS_DOWNLOADER = ARGS_COMMON + ["pairs", "pairs_file", "days", "exchange", "timeframes", "erase"]
ARGS_PLOT_DATAFRAME = (ARGS_COMMON + ARGS_STRATEGY +
2019-06-22 18:32:54 +00:00
["pairs", "indicators1", "indicators2", "plot_limit", "db_url",
"trade_source", "export", "exportfilename", "timerange",
"refresh_pairs", "live"])
2019-06-22 18:27:29 +00:00
ARGS_PLOT_PROFIT = (ARGS_COMMON + ARGS_STRATEGY +
2019-06-29 14:57:04 +00:00
["pairs", "timerange", "export", "exportfilename", "db_url", "trade_source"])
2019-06-22 18:27:29 +00:00
2018-06-05 21:34:26 +00:00
class TimeRange(NamedTuple):
2018-06-05 22:10:18 +00:00
"""
2019-07-06 22:20:26 +00:00
NamedTuple defining timerange inputs.
2018-06-05 22:10:18 +00:00
[start/stop]type defines if [start/stop]ts shall be used.
2019-07-06 22:20:26 +00:00
if *type is None, don't use corresponding startvalue.
2018-06-05 22:10:18 +00:00
"""
2018-06-05 21:34:26 +00:00
starttype: Optional[str] = None
stoptype: Optional[str] = None
startts: int = 0
stopts: int = 0
class Arguments(object):
"""
Arguments Class. Manage the arguments received by the cli
"""
def __init__(self, args: Optional[List[str]], description: str,
no_default_config: bool = False) -> None:
self.args = args
self._parsed_arg: Optional[argparse.Namespace] = None
self.parser = argparse.ArgumentParser(description=description)
self._no_default_config = no_default_config
2018-03-17 21:20:45 +00:00
def _load_args(self) -> None:
self._build_args(optionlist=ARGS_MAIN)
self._build_subcommands()
2018-03-17 23:02:02 +00:00
def get_parsed_arg(self) -> argparse.Namespace:
"""
Return the list of arguments
:return: List[str] List of arguments
"""
if self._parsed_arg is None:
self._load_args()
self._parsed_arg = self._parse_args()
return self._parsed_arg
def _parse_args(self) -> argparse.Namespace:
"""
Parses given arguments and returns an argparse Namespace instance.
"""
parsed_arg = self.parser.parse_args(self.args)
2019-02-19 12:14:47 +00:00
# Workaround issue in argparse with action='append' and default value
# (see https://bugs.python.org/issue16399)
if not self._no_default_config and parsed_arg.config is None:
2019-02-19 12:14:47 +00:00
parsed_arg.config = [constants.DEFAULT_CONFIG]
return parsed_arg
def _build_args(self, optionlist, parser=None):
parser = parser or self.parser
for val in optionlist:
opt = AVAILABLE_CLI_OPTIONS[val]
parser.add_argument(*opt.cli, dest=val, **opt.kwargs)
def _build_subcommands(self) -> None:
"""
2019-06-18 22:53:38 +00:00
Builds and attaches all subcommands.
:return: None
"""
from freqtrade.optimize import start_backtesting, start_hyperopt, start_edge
from freqtrade.utils import start_create_userdir, start_list_exchanges
subparsers = self.parser.add_subparsers(dest='subparser')
# Add backtesting subcommand
2019-02-19 12:14:47 +00:00
backtesting_cmd = subparsers.add_parser('backtesting', help='Backtesting module.')
backtesting_cmd.set_defaults(func=start_backtesting)
self._build_args(optionlist=ARGS_BACKTEST, parser=backtesting_cmd)
2018-11-14 11:37:15 +00:00
# Add edge subcommand
2019-02-19 12:14:47 +00:00
edge_cmd = subparsers.add_parser('edge', help='Edge module.')
edge_cmd.set_defaults(func=start_edge)
self._build_args(optionlist=ARGS_EDGE, parser=edge_cmd)
2018-11-14 11:37:15 +00:00
# Add hyperopt subcommand
2019-02-19 12:14:47 +00:00
hyperopt_cmd = subparsers.add_parser('hyperopt', help='Hyperopt module.')
hyperopt_cmd.set_defaults(func=start_hyperopt)
self._build_args(optionlist=ARGS_HYPEROPT, parser=hyperopt_cmd)
create_userdir_cmd = subparsers.add_parser('create-userdir',
help="Create user-data directory.")
create_userdir_cmd.set_defaults(func=start_create_userdir)
self._build_args(optionlist=ARGS_CREATE_USERDIR, parser=create_userdir_cmd)
2019-06-12 09:33:20 +00:00
# Add list-exchanges subcommand
2019-06-14 19:04:29 +00:00
list_exchanges_cmd = subparsers.add_parser(
'list-exchanges',
help='Print available exchanges.'
)
2019-06-12 09:33:20 +00:00
list_exchanges_cmd.set_defaults(func=start_list_exchanges)
self._build_args(optionlist=ARGS_LIST_EXCHANGES, parser=list_exchanges_cmd)
2019-06-12 09:33:20 +00:00
@staticmethod
2018-06-05 21:34:26 +00:00
def parse_timerange(text: Optional[str]) -> TimeRange:
"""
Parse the value of the argument --timerange to determine what is the range desired
:param text: value from --timerange
:return: Start and End range period
"""
if text is None:
return TimeRange(None, None, 0, 0)
syntax = [(r'^-(\d{8})$', (None, 'date')),
(r'^(\d{8})-$', ('date', None)),
(r'^(\d{8})-(\d{8})$', ('date', 'date')),
(r'^-(\d{10})$', (None, 'date')),
(r'^(\d{10})-$', ('date', None)),
(r'^(\d{10})-(\d{10})$', ('date', 'date')),
(r'^(-\d+)$', (None, 'line')),
(r'^(\d+)-$', ('line', None)),
(r'^(\d+)-(\d+)$', ('index', 'index'))]
for rex, stype in syntax:
# Apply the regular expression to text
match = re.match(rex, text)
if match: # Regex has matched
rvals = match.groups()
index = 0
2018-06-05 21:34:26 +00:00
start: int = 0
stop: int = 0
if stype[0]:
starts = rvals[index]
2018-06-05 21:14:28 +00:00
if stype[0] == 'date' and len(starts) == 8:
start = arrow.get(starts, 'YYYYMMDD').timestamp
else:
start = int(starts)
index += 1
if stype[1]:
stops = rvals[index]
2018-06-05 21:14:28 +00:00
if stype[1] == 'date' and len(stops) == 8:
stop = arrow.get(stops, 'YYYYMMDD').timestamp
else:
stop = int(stops)
2018-06-05 21:34:26 +00:00
return TimeRange(stype[0], stype[1], start, stop)
raise Exception('Incorrect syntax for timerange "%s"' % text)