Merge branch 'develop' into hyperopt-opt-params
This commit is contained in:
commit
fc4ef2b430
@ -146,7 +146,9 @@ Backtesting also uses the config specified via `-c/--config`.
|
|||||||
|
|
||||||
```
|
```
|
||||||
usage: freqtrade backtesting [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
usage: freqtrade backtesting [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
||||||
[--eps] [--dmmp] [-l] [-r]
|
[--max_open_trades MAX_OPEN_TRADES]
|
||||||
|
[--stake_amount STAKE_AMOUNT] [-r] [--eps] [--dmmp]
|
||||||
|
[-l]
|
||||||
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
||||||
[--export EXPORT] [--export-filename PATH]
|
[--export EXPORT] [--export-filename PATH]
|
||||||
|
|
||||||
@ -156,6 +158,14 @@ optional arguments:
|
|||||||
Specify ticker interval (1m, 5m, 30m, 1h, 1d).
|
Specify ticker interval (1m, 5m, 30m, 1h, 1d).
|
||||||
--timerange TIMERANGE
|
--timerange TIMERANGE
|
||||||
Specify what timerange of data to use.
|
Specify what timerange of data to use.
|
||||||
|
--max_open_trades MAX_OPEN_TRADES
|
||||||
|
Specify max_open_trades to use.
|
||||||
|
--stake_amount STAKE_AMOUNT
|
||||||
|
Specify stake_amount.
|
||||||
|
-r, --refresh-pairs-cached
|
||||||
|
Refresh the pairs files in tests/testdata with the
|
||||||
|
latest data from the exchange. Use it if you want to
|
||||||
|
run your optimization commands with up-to-date data.
|
||||||
--eps, --enable-position-stacking
|
--eps, --enable-position-stacking
|
||||||
Allow buying the same pair multiple times (position
|
Allow buying the same pair multiple times (position
|
||||||
stacking).
|
stacking).
|
||||||
@ -164,10 +174,6 @@ optional arguments:
|
|||||||
(same as setting `max_open_trades` to a very high
|
(same as setting `max_open_trades` to a very high
|
||||||
number).
|
number).
|
||||||
-l, --live Use live data.
|
-l, --live Use live data.
|
||||||
-r, --refresh-pairs-cached
|
|
||||||
Refresh the pairs files in tests/testdata with the
|
|
||||||
latest data from the exchange. Use it if you want to
|
|
||||||
run your backtesting with up-to-date data.
|
|
||||||
--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]
|
--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]
|
||||||
Provide a commaseparated list of strategies to
|
Provide a commaseparated list of strategies to
|
||||||
backtest Please note that ticker-interval needs to be
|
backtest Please note that ticker-interval needs to be
|
||||||
@ -206,8 +212,11 @@ to find optimal parameter values for your stategy.
|
|||||||
|
|
||||||
```
|
```
|
||||||
usage: freqtrade hyperopt [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
usage: freqtrade hyperopt [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
||||||
|
[--max_open_trades MAX_OPEN_TRADES]
|
||||||
|
[--stake_amount STAKE_AMOUNT] [-r]
|
||||||
[--customhyperopt NAME] [--eps] [--dmmp] [-e INT]
|
[--customhyperopt NAME] [--eps] [--dmmp] [-e INT]
|
||||||
[-s {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]]
|
[-s {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]]
|
||||||
|
[--print-all]
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@ -215,6 +224,14 @@ optional arguments:
|
|||||||
Specify ticker interval (1m, 5m, 30m, 1h, 1d).
|
Specify ticker interval (1m, 5m, 30m, 1h, 1d).
|
||||||
--timerange TIMERANGE
|
--timerange TIMERANGE
|
||||||
Specify what timerange of data to use.
|
Specify what timerange of data to use.
|
||||||
|
--max_open_trades MAX_OPEN_TRADES
|
||||||
|
Specify max_open_trades to use.
|
||||||
|
--stake_amount STAKE_AMOUNT
|
||||||
|
Specify stake_amount.
|
||||||
|
-r, --refresh-pairs-cached
|
||||||
|
Refresh the pairs files in tests/testdata with the
|
||||||
|
latest data from the exchange. Use it if you want to
|
||||||
|
run your optimization commands with up-to-date data.
|
||||||
--customhyperopt NAME
|
--customhyperopt NAME
|
||||||
Specify hyperopt class name (default:
|
Specify hyperopt class name (default:
|
||||||
DefaultHyperOpts).
|
DefaultHyperOpts).
|
||||||
@ -229,7 +246,7 @@ optional arguments:
|
|||||||
-s {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...], --spaces {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]
|
-s {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...], --spaces {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]
|
||||||
Specify which parameters to hyperopt. Space separate
|
Specify which parameters to hyperopt. Space separate
|
||||||
list. Default: all.
|
list. Default: all.
|
||||||
|
--print-all Print all results, not only the best ones.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Edge commands
|
## Edge commands
|
||||||
@ -237,7 +254,9 @@ optional arguments:
|
|||||||
To know your trade expectacny and winrate against historical data, you can use Edge.
|
To know your trade expectacny and winrate against historical data, you can use Edge.
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: freqtrade edge [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE] [-r]
|
usage: freqtrade edge [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
||||||
|
[--max_open_trades MAX_OPEN_TRADES]
|
||||||
|
[--stake_amount STAKE_AMOUNT] [-r]
|
||||||
[--stoplosses STOPLOSS_RANGE]
|
[--stoplosses STOPLOSS_RANGE]
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
@ -246,10 +265,14 @@ optional arguments:
|
|||||||
Specify ticker interval (1m, 5m, 30m, 1h, 1d).
|
Specify ticker interval (1m, 5m, 30m, 1h, 1d).
|
||||||
--timerange TIMERANGE
|
--timerange TIMERANGE
|
||||||
Specify what timerange of data to use.
|
Specify what timerange of data to use.
|
||||||
|
--max_open_trades MAX_OPEN_TRADES
|
||||||
|
Specify max_open_trades to use.
|
||||||
|
--stake_amount STAKE_AMOUNT
|
||||||
|
Specify stake_amount.
|
||||||
-r, --refresh-pairs-cached
|
-r, --refresh-pairs-cached
|
||||||
Refresh the pairs files in tests/testdata with the
|
Refresh the pairs files in tests/testdata with the
|
||||||
latest data from the exchange. Use it if you want to
|
latest data from the exchange. Use it if you want to
|
||||||
run your edge with up-to-date data.
|
run your optimization commands with up-to-date data.
|
||||||
--stoplosses STOPLOSS_RANGE
|
--stoplosses STOPLOSS_RANGE
|
||||||
Defines a range of stoploss against which edge will
|
Defines a range of stoploss against which edge will
|
||||||
assess the strategy the format is "min,max,step"
|
assess the strategy the format is "min,max,step"
|
||||||
|
@ -141,10 +141,53 @@ class Arguments(object):
|
|||||||
dest='sd_notify',
|
dest='sd_notify',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def optimizer_shared_options(parser: argparse.ArgumentParser) -> None:
|
||||||
|
"""
|
||||||
|
Parses given common arguments for Backtesting, Edge and Hyperopt modules.
|
||||||
|
:param parser:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
parser.add_argument(
|
||||||
|
'-i', '--ticker-interval',
|
||||||
|
help='Specify ticker interval (1m, 5m, 30m, 1h, 1d).',
|
||||||
|
dest='ticker_interval',
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--timerange',
|
||||||
|
help='Specify what timerange of data to use.',
|
||||||
|
default=None,
|
||||||
|
type=str,
|
||||||
|
dest='timerange',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--max_open_trades',
|
||||||
|
help='Specify max_open_trades to use.',
|
||||||
|
default=None,
|
||||||
|
type=int,
|
||||||
|
dest='max_open_trades',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--stake_amount',
|
||||||
|
help='Specify stake_amount.',
|
||||||
|
default=None,
|
||||||
|
type=float,
|
||||||
|
dest='stake_amount',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-r', '--refresh-pairs-cached',
|
||||||
|
help='Refresh the pairs files in tests/testdata with the latest data from the '
|
||||||
|
'exchange. Use it if you want to run your optimization commands with '
|
||||||
|
'up-to-date data.',
|
||||||
|
action='store_true',
|
||||||
|
dest='refresh_pairs',
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def backtesting_options(parser: argparse.ArgumentParser) -> None:
|
def backtesting_options(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
Parses given arguments for Backtesting scripts.
|
Parses given arguments for Backtesting module.
|
||||||
"""
|
"""
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--eps', '--enable-position-stacking',
|
'--eps', '--enable-position-stacking',
|
||||||
@ -167,13 +210,6 @@ class Arguments(object):
|
|||||||
action='store_true',
|
action='store_true',
|
||||||
dest='live',
|
dest='live',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
'-r', '--refresh-pairs-cached',
|
|
||||||
help='Refresh the pairs files in tests/testdata with the latest data from the '
|
|
||||||
'exchange. Use it if you want to run your backtesting with up-to-date data.',
|
|
||||||
action='store_true',
|
|
||||||
dest='refresh_pairs',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--strategy-list',
|
'--strategy-list',
|
||||||
help='Provide a commaseparated list of strategies to backtest '
|
help='Provide a commaseparated list of strategies to backtest '
|
||||||
@ -207,15 +243,8 @@ class Arguments(object):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def edge_options(parser: argparse.ArgumentParser) -> None:
|
def edge_options(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
Parses given arguments for Backtesting scripts.
|
Parses given arguments for Edge module.
|
||||||
"""
|
"""
|
||||||
parser.add_argument(
|
|
||||||
'-r', '--refresh-pairs-cached',
|
|
||||||
help='Refresh the pairs files in tests/testdata with the latest data from the '
|
|
||||||
'exchange. Use it if you want to run your edge with up-to-date data.',
|
|
||||||
action='store_true',
|
|
||||||
dest='refresh_pairs',
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--stoplosses',
|
'--stoplosses',
|
||||||
help='Defines a range of stoploss against which edge will assess the strategy '
|
help='Defines a range of stoploss against which edge will assess the strategy '
|
||||||
@ -225,48 +254,10 @@ class Arguments(object):
|
|||||||
dest='stoploss_range',
|
dest='stoploss_range',
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def optimizer_shared_options(parser: argparse.ArgumentParser) -> None:
|
|
||||||
"""
|
|
||||||
Parses given common arguments for Backtesting and Hyperopt scripts.
|
|
||||||
:param parser:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
parser.add_argument(
|
|
||||||
'-i', '--ticker-interval',
|
|
||||||
help='Specify ticker interval (1m, 5m, 30m, 1h, 1d).',
|
|
||||||
dest='ticker_interval',
|
|
||||||
type=str,
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--timerange',
|
|
||||||
help='Specify what timerange of data to use.',
|
|
||||||
default=None,
|
|
||||||
type=str,
|
|
||||||
dest='timerange',
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--max_open_trades',
|
|
||||||
help='Specify max_open_trades to use.',
|
|
||||||
default=None,
|
|
||||||
type=int,
|
|
||||||
dest='max_open_trades',
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--stake_amount',
|
|
||||||
help='Specify stake_amount.',
|
|
||||||
default=None,
|
|
||||||
type=float,
|
|
||||||
dest='stake_amount',
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def hyperopt_options(parser: argparse.ArgumentParser) -> None:
|
def hyperopt_options(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
Parses given arguments for Hyperopt scripts.
|
Parses given arguments for Hyperopt module.
|
||||||
"""
|
"""
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--customhyperopt',
|
'--customhyperopt',
|
||||||
|
@ -201,24 +201,20 @@ class Configuration(object):
|
|||||||
:return: configuration as dictionary
|
:return: configuration as dictionary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# If -i/--ticker-interval is used we override the configuration parameter
|
# This will override the strategy configuration
|
||||||
# (that will override the strategy configuration)
|
|
||||||
if 'ticker_interval' in self.args and self.args.ticker_interval:
|
if 'ticker_interval' in self.args and self.args.ticker_interval:
|
||||||
config.update({'ticker_interval': self.args.ticker_interval})
|
config.update({'ticker_interval': self.args.ticker_interval})
|
||||||
logger.info('Parameter -i/--ticker-interval detected ...')
|
logger.info('Parameter -i/--ticker-interval detected ...')
|
||||||
logger.info('Using ticker_interval: %s ...', config.get('ticker_interval'))
|
logger.info('Using ticker_interval: %s ...', config.get('ticker_interval'))
|
||||||
|
|
||||||
# If -l/--live is used we add it to the configuration
|
|
||||||
if 'live' in self.args and self.args.live:
|
if 'live' in self.args and self.args.live:
|
||||||
config.update({'live': True})
|
config.update({'live': True})
|
||||||
logger.info('Parameter -l/--live detected ...')
|
logger.info('Parameter -l/--live detected ...')
|
||||||
|
|
||||||
# If --enable-position-stacking is used we add it to the configuration
|
|
||||||
if 'position_stacking' in self.args and self.args.position_stacking:
|
if 'position_stacking' in self.args and self.args.position_stacking:
|
||||||
config.update({'position_stacking': True})
|
config.update({'position_stacking': True})
|
||||||
logger.info('Parameter --enable-position-stacking detected ...')
|
logger.info('Parameter --enable-position-stacking detected ...')
|
||||||
|
|
||||||
# If --disable-max-market-positions or --max_open_trades is used we update configuration
|
|
||||||
if 'use_max_market_positions' in self.args and not self.args.use_max_market_positions:
|
if 'use_max_market_positions' in self.args and not self.args.use_max_market_positions:
|
||||||
config.update({'use_max_market_positions': False})
|
config.update({'use_max_market_positions': False})
|
||||||
logger.info('Parameter --disable-max-market-positions detected ...')
|
logger.info('Parameter --disable-max-market-positions detected ...')
|
||||||
@ -230,25 +226,21 @@ class Configuration(object):
|
|||||||
else:
|
else:
|
||||||
logger.info('Using max_open_trades: %s ...', config.get('max_open_trades'))
|
logger.info('Using max_open_trades: %s ...', config.get('max_open_trades'))
|
||||||
|
|
||||||
# If --stake_amount is used we update configuration
|
|
||||||
if 'stake_amount' in self.args and self.args.stake_amount:
|
if 'stake_amount' in self.args and self.args.stake_amount:
|
||||||
config.update({'stake_amount': self.args.stake_amount})
|
config.update({'stake_amount': self.args.stake_amount})
|
||||||
logger.info('Parameter --stake_amount detected, overriding stake_amount to: %s ...',
|
logger.info('Parameter --stake_amount detected, overriding stake_amount to: %s ...',
|
||||||
config.get('stake_amount'))
|
config.get('stake_amount'))
|
||||||
|
|
||||||
# If --timerange is used we add it to the configuration
|
|
||||||
if 'timerange' in self.args and self.args.timerange:
|
if 'timerange' in self.args and self.args.timerange:
|
||||||
config.update({'timerange': self.args.timerange})
|
config.update({'timerange': self.args.timerange})
|
||||||
logger.info('Parameter --timerange detected: %s ...', self.args.timerange)
|
logger.info('Parameter --timerange detected: %s ...', self.args.timerange)
|
||||||
|
|
||||||
# If --datadir is used we add it to the configuration
|
|
||||||
if 'datadir' in self.args and self.args.datadir:
|
if 'datadir' in self.args and self.args.datadir:
|
||||||
config.update({'datadir': self._create_datadir(config, self.args.datadir)})
|
config.update({'datadir': self._create_datadir(config, self.args.datadir)})
|
||||||
else:
|
else:
|
||||||
config.update({'datadir': self._create_datadir(config, None)})
|
config.update({'datadir': self._create_datadir(config, None)})
|
||||||
logger.info('Using data folder: %s ...', config.get('datadir'))
|
logger.info('Using data folder: %s ...', config.get('datadir'))
|
||||||
|
|
||||||
# If -r/--refresh-pairs-cached is used we add it to the configuration
|
|
||||||
if 'refresh_pairs' in self.args and self.args.refresh_pairs:
|
if 'refresh_pairs' in self.args and self.args.refresh_pairs:
|
||||||
config.update({'refresh_pairs': True})
|
config.update({'refresh_pairs': True})
|
||||||
logger.info('Parameter -r/--refresh-pairs-cached detected ...')
|
logger.info('Parameter -r/--refresh-pairs-cached detected ...')
|
||||||
@ -261,12 +253,10 @@ class Configuration(object):
|
|||||||
config.update({'ticker_interval': self.args.ticker_interval})
|
config.update({'ticker_interval': self.args.ticker_interval})
|
||||||
logger.info('Overriding ticker interval with Command line argument')
|
logger.info('Overriding ticker interval with Command line argument')
|
||||||
|
|
||||||
# If --export is used we add it to the configuration
|
|
||||||
if 'export' in self.args and self.args.export:
|
if 'export' in self.args and self.args.export:
|
||||||
config.update({'export': self.args.export})
|
config.update({'export': self.args.export})
|
||||||
logger.info('Parameter --export detected: %s ...', self.args.export)
|
logger.info('Parameter --export detected: %s ...', self.args.export)
|
||||||
|
|
||||||
# If --export-filename is used we add it to the configuration
|
|
||||||
if 'export' in config and 'exportfilename' in self.args and self.args.exportfilename:
|
if 'export' in config and 'exportfilename' in self.args and self.args.exportfilename:
|
||||||
config.update({'exportfilename': self.args.exportfilename})
|
config.update({'exportfilename': self.args.exportfilename})
|
||||||
logger.info('Storing backtest results to %s ...', self.args.exportfilename)
|
logger.info('Storing backtest results to %s ...', self.args.exportfilename)
|
||||||
@ -279,12 +269,10 @@ class Configuration(object):
|
|||||||
:return: configuration as dictionary
|
:return: configuration as dictionary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# If --timerange is used we add it to the configuration
|
|
||||||
if 'timerange' in self.args and self.args.timerange:
|
if 'timerange' in self.args and self.args.timerange:
|
||||||
config.update({'timerange': self.args.timerange})
|
config.update({'timerange': self.args.timerange})
|
||||||
logger.info('Parameter --timerange detected: %s ...', self.args.timerange)
|
logger.info('Parameter --timerange detected: %s ...', self.args.timerange)
|
||||||
|
|
||||||
# If --timerange is used we add it to the configuration
|
|
||||||
if 'stoploss_range' in self.args and self.args.stoploss_range:
|
if 'stoploss_range' in self.args and self.args.stoploss_range:
|
||||||
txt_range = eval(self.args.stoploss_range)
|
txt_range = eval(self.args.stoploss_range)
|
||||||
config['edge'].update({'stoploss_range_min': txt_range[0]})
|
config['edge'].update({'stoploss_range_min': txt_range[0]})
|
||||||
@ -292,7 +280,6 @@ class Configuration(object):
|
|||||||
config['edge'].update({'stoploss_range_step': txt_range[2]})
|
config['edge'].update({'stoploss_range_step': txt_range[2]})
|
||||||
logger.info('Parameter --stoplosses detected: %s ...', self.args.stoploss_range)
|
logger.info('Parameter --stoplosses detected: %s ...', self.args.stoploss_range)
|
||||||
|
|
||||||
# If -r/--refresh-pairs-cached is used we add it to the configuration
|
|
||||||
if 'refresh_pairs' in self.args and self.args.refresh_pairs:
|
if 'refresh_pairs' in self.args and self.args.refresh_pairs:
|
||||||
config.update({'refresh_pairs': True})
|
config.update({'refresh_pairs': True})
|
||||||
logger.info('Parameter -r/--refresh-pairs-cached detected ...')
|
logger.info('Parameter -r/--refresh-pairs-cached detected ...')
|
||||||
@ -309,13 +296,11 @@ class Configuration(object):
|
|||||||
# Add the hyperopt file to use
|
# Add the hyperopt file to use
|
||||||
config.update({'hyperopt': self.args.hyperopt})
|
config.update({'hyperopt': self.args.hyperopt})
|
||||||
|
|
||||||
# If --epochs is used we add it to the configuration
|
|
||||||
if 'epochs' in self.args and self.args.epochs:
|
if 'epochs' in self.args and self.args.epochs:
|
||||||
config.update({'epochs': self.args.epochs})
|
config.update({'epochs': self.args.epochs})
|
||||||
logger.info('Parameter --epochs detected ...')
|
logger.info('Parameter --epochs detected ...')
|
||||||
logger.info('Will run Hyperopt with for %s epochs ...', config.get('epochs'))
|
logger.info('Will run Hyperopt with for %s epochs ...', config.get('epochs'))
|
||||||
|
|
||||||
# If --spaces is used we add it to the configuration
|
|
||||||
if 'spaces' in self.args and self.args.spaces:
|
if 'spaces' in self.args and self.args.spaces:
|
||||||
config.update({'spaces': self.args.spaces})
|
config.update({'spaces': self.args.spaces})
|
||||||
logger.info('Parameter -s/--spaces detected: %s', config.get('spaces'))
|
logger.info('Parameter -s/--spaces detected: %s', config.get('spaces'))
|
||||||
@ -324,6 +309,10 @@ class Configuration(object):
|
|||||||
config.update({'print_all': self.args.print_all})
|
config.update({'print_all': self.args.print_all})
|
||||||
logger.info('Parameter --print-all detected: %s', config.get('print_all'))
|
logger.info('Parameter --print-all detected: %s', config.get('print_all'))
|
||||||
|
|
||||||
|
if 'refresh_pairs' in self.args and self.args.refresh_pairs:
|
||||||
|
config.update({'refresh_pairs': True})
|
||||||
|
logger.info('Parameter -r/--refresh-pairs-cached detected ...')
|
||||||
|
|
||||||
if 'hyperopt_random_state' in self.args and self.args.hyperopt_random_state is not None:
|
if 'hyperopt_random_state' in self.args and self.args.hyperopt_random_state is not None:
|
||||||
config.update({'hyperopt_random_state': self.args.hyperopt_random_state})
|
config.update({'hyperopt_random_state': self.args.hyperopt_random_state})
|
||||||
logger.info("Parameter --random-state detected: %s", config.get('hyperopt_random_state'))
|
logger.info("Parameter --random-state detected: %s", config.get('hyperopt_random_state'))
|
||||||
|
@ -116,7 +116,8 @@ def load_pair_history(pair: str,
|
|||||||
return parse_ticker_dataframe(pairdata, ticker_interval, fill_up_missing)
|
return parse_ticker_dataframe(pairdata, ticker_interval, fill_up_missing)
|
||||||
else:
|
else:
|
||||||
logger.warning('No data for pair: "%s", Interval: %s. '
|
logger.warning('No data for pair: "%s", Interval: %s. '
|
||||||
'Use --refresh-pairs-cached to download the data',
|
'Use --refresh-pairs-cached option or download_backtest_data.py '
|
||||||
|
'script to download the data',
|
||||||
pair, ticker_interval)
|
pair, ticker_interval)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -516,6 +516,7 @@ def start(args: Namespace) -> None:
|
|||||||
"""
|
"""
|
||||||
# Initialize configuration
|
# Initialize configuration
|
||||||
config = setup_configuration(args)
|
config = setup_configuration(args)
|
||||||
|
|
||||||
logger.info('Starting freqtrade in Backtesting mode')
|
logger.info('Starting freqtrade in Backtesting mode')
|
||||||
|
|
||||||
# Initialize backtesting object
|
# Initialize backtesting object
|
||||||
|
@ -20,6 +20,7 @@ from pandas import DataFrame
|
|||||||
from skopt import Optimizer
|
from skopt import Optimizer
|
||||||
from skopt.space import Dimension
|
from skopt.space import Dimension
|
||||||
|
|
||||||
|
from freqtrade import DependencyException
|
||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.configuration import Configuration
|
from freqtrade.configuration import Configuration
|
||||||
from freqtrade.data.history import load_data
|
from freqtrade.data.history import load_data
|
||||||
@ -259,6 +260,8 @@ class Hyperopt(Backtesting):
|
|||||||
datadir=Path(self.config['datadir']) if self.config.get('datadir') else None,
|
datadir=Path(self.config['datadir']) if self.config.get('datadir') else None,
|
||||||
pairs=self.config['exchange']['pair_whitelist'],
|
pairs=self.config['exchange']['pair_whitelist'],
|
||||||
ticker_interval=self.ticker_interval,
|
ticker_interval=self.ticker_interval,
|
||||||
|
refresh_pairs=self.config.get('refresh_pairs', False),
|
||||||
|
exchange=self.exchange,
|
||||||
timerange=timerange
|
timerange=timerange
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -266,7 +269,10 @@ class Hyperopt(Backtesting):
|
|||||||
self.strategy.advise_indicators = \
|
self.strategy.advise_indicators = \
|
||||||
self.custom_hyperopt.populate_indicators # type: ignore
|
self.custom_hyperopt.populate_indicators # type: ignore
|
||||||
dump(self.strategy.tickerdata_to_dataframe(data), TICKERDATA_PICKLE)
|
dump(self.strategy.tickerdata_to_dataframe(data), TICKERDATA_PICKLE)
|
||||||
|
|
||||||
|
# We don't need exchange instance anymore while running hyperopt
|
||||||
self.exchange = None # type: ignore
|
self.exchange = None # type: ignore
|
||||||
|
|
||||||
self.load_previous_results()
|
self.load_previous_results()
|
||||||
|
|
||||||
cpus = multiprocessing.cpu_count()
|
cpus = multiprocessing.cpu_count()
|
||||||
@ -289,6 +295,9 @@ class Hyperopt(Backtesting):
|
|||||||
'total_tries': self.total_tries,
|
'total_tries': self.total_tries,
|
||||||
'result': f_val[j]['result'],
|
'result': f_val[j]['result'],
|
||||||
})
|
})
|
||||||
|
logger.debug(f"Optimizer params: {f_val[j]['params']}")
|
||||||
|
for j in range(cpus):
|
||||||
|
logger.debug(f"Opimizer state: Xi: {opt.Xi[-j-1]}, yi: {opt.yi[-j-1]}")
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print('User interrupted..')
|
print('User interrupted..')
|
||||||
|
|
||||||
@ -296,22 +305,16 @@ class Hyperopt(Backtesting):
|
|||||||
self.log_trials_result()
|
self.log_trials_result()
|
||||||
|
|
||||||
|
|
||||||
def start(args: Namespace) -> None:
|
def setup_configuration(args: Namespace) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Start Backtesting script
|
Prepare the configuration for the Hyperopt module
|
||||||
:param args: Cli args from Arguments()
|
:param args: Cli args from Arguments()
|
||||||
:return: None
|
:return: Configuration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Remove noisy log messages
|
|
||||||
logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING)
|
|
||||||
|
|
||||||
# Initialize configuration
|
|
||||||
# Monkey patch the configuration with hyperopt_conf.py
|
|
||||||
configuration = Configuration(args, RunMode.HYPEROPT)
|
configuration = Configuration(args, RunMode.HYPEROPT)
|
||||||
logger.info('Starting freqtrade in Hyperopt mode')
|
|
||||||
config = configuration.load_config()
|
config = configuration.load_config()
|
||||||
|
|
||||||
|
# Ensure we do not use Exchange credentials
|
||||||
config['exchange']['key'] = ''
|
config['exchange']['key'] = ''
|
||||||
config['exchange']['secret'] = ''
|
config['exchange']['secret'] = ''
|
||||||
|
|
||||||
@ -321,7 +324,25 @@ def start(args: Namespace) -> None:
|
|||||||
"Read the documentation at "
|
"Read the documentation at "
|
||||||
"https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md "
|
"https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md "
|
||||||
"to understand how to configure hyperopt.")
|
"to understand how to configure hyperopt.")
|
||||||
raise ValueError("--strategy configured but not supported for hyperopt")
|
raise DependencyException("--strategy configured but not supported for hyperopt")
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def start(args: Namespace) -> None:
|
||||||
|
"""
|
||||||
|
Start Backtesting script
|
||||||
|
:param args: Cli args from Arguments()
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
# Initialize configuration
|
||||||
|
config = setup_configuration(args)
|
||||||
|
|
||||||
|
logger.info('Starting freqtrade in Hyperopt mode')
|
||||||
|
|
||||||
|
# Remove noisy log messages
|
||||||
|
logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING)
|
||||||
|
|
||||||
# Initialize backtesting object
|
# Initialize backtesting object
|
||||||
hyperopt = Hyperopt(config)
|
hyperopt = Hyperopt(config)
|
||||||
hyperopt.start()
|
hyperopt.start()
|
||||||
|
@ -68,7 +68,10 @@ def test_load_data_7min_ticker(mocker, caplog, default_conf) -> None:
|
|||||||
assert ld is None
|
assert ld is None
|
||||||
assert log_has(
|
assert log_has(
|
||||||
'No data for pair: "UNITTEST/BTC", Interval: 7m. '
|
'No data for pair: "UNITTEST/BTC", Interval: 7m. '
|
||||||
'Use --refresh-pairs-cached to download the data', caplog.record_tuples)
|
'Use --refresh-pairs-cached option or download_backtest_data.py '
|
||||||
|
'script to download the data',
|
||||||
|
caplog.record_tuples
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_load_data_1min_ticker(ticker_history, mocker, caplog) -> None:
|
def test_load_data_1min_ticker(ticker_history, mocker, caplog) -> None:
|
||||||
@ -96,9 +99,12 @@ def test_load_data_with_new_pair_1min(ticker_history_list, mocker, caplog, defau
|
|||||||
refresh_pairs=False,
|
refresh_pairs=False,
|
||||||
pair='MEME/BTC')
|
pair='MEME/BTC')
|
||||||
assert os.path.isfile(file) is False
|
assert os.path.isfile(file) is False
|
||||||
assert log_has('No data for pair: "MEME/BTC", Interval: 1m. '
|
assert log_has(
|
||||||
'Use --refresh-pairs-cached to download the data',
|
'No data for pair: "MEME/BTC", Interval: 1m. '
|
||||||
caplog.record_tuples)
|
'Use --refresh-pairs-cached option or download_backtest_data.py '
|
||||||
|
'script to download the data',
|
||||||
|
caplog.record_tuples
|
||||||
|
)
|
||||||
|
|
||||||
# download a new pair if refresh_pairs is set
|
# download a new pair if refresh_pairs is set
|
||||||
history.load_pair_history(datadir=None,
|
history.load_pair_history(datadir=None,
|
||||||
|
@ -260,6 +260,7 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) ->
|
|||||||
|
|
||||||
assert 'refresh_pairs' in config
|
assert 'refresh_pairs' in config
|
||||||
assert log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
assert log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'timerange' in config
|
assert 'timerange' in config
|
||||||
assert log_has(
|
assert log_has(
|
||||||
'Parameter --timerange detected: {} ...'.format(config['timerange']),
|
'Parameter --timerange detected: {} ...'.format(config['timerange']),
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
# pragma pylint: disable=missing-docstring,W0212,C0103
|
# pragma pylint: disable=missing-docstring,W0212,C0103
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from freqtrade import DependencyException
|
||||||
from freqtrade.data.converter import parse_ticker_dataframe
|
from freqtrade.data.converter import parse_ticker_dataframe
|
||||||
from freqtrade.data.history import load_tickerdata_file
|
from freqtrade.data.history import load_tickerdata_file
|
||||||
from freqtrade.optimize.hyperopt import Hyperopt, start
|
from freqtrade.optimize.hyperopt import Hyperopt, start, setup_configuration
|
||||||
from freqtrade.optimize.default_hyperopt import DefaultHyperOpts
|
from freqtrade.optimize.default_hyperopt import DefaultHyperOpts
|
||||||
from freqtrade.resolvers import StrategyResolver, HyperOptResolver
|
from freqtrade.resolvers import StrategyResolver, HyperOptResolver
|
||||||
|
from freqtrade.state import RunMode
|
||||||
from freqtrade.tests.conftest import log_has, patch_exchange
|
from freqtrade.tests.conftest import log_has, patch_exchange
|
||||||
from freqtrade.tests.optimize.test_backtesting import get_args
|
from freqtrade.tests.optimize.test_backtesting import get_args
|
||||||
|
|
||||||
@ -39,6 +42,112 @@ def create_trials(mocker, hyperopt) -> None:
|
|||||||
return [{'loss': 1, 'result': 'foo', 'params': {}}]
|
return [{'loss': 1, 'result': 'foo', 'params': {}}]
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, caplog) -> None:
|
||||||
|
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
|
||||||
|
read_data=json.dumps(default_conf)
|
||||||
|
))
|
||||||
|
|
||||||
|
args = [
|
||||||
|
'--config', 'config.json',
|
||||||
|
'hyperopt'
|
||||||
|
]
|
||||||
|
|
||||||
|
config = setup_configuration(get_args(args))
|
||||||
|
assert 'max_open_trades' in config
|
||||||
|
assert 'stake_currency' in config
|
||||||
|
assert 'stake_amount' in config
|
||||||
|
assert 'exchange' in config
|
||||||
|
assert 'pair_whitelist' in config['exchange']
|
||||||
|
assert 'datadir' in config
|
||||||
|
assert log_has(
|
||||||
|
'Using data folder: {} ...'.format(config['datadir']),
|
||||||
|
caplog.record_tuples
|
||||||
|
)
|
||||||
|
assert 'ticker_interval' in config
|
||||||
|
assert not log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
assert 'live' not in config
|
||||||
|
assert not log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
assert 'position_stacking' not in config
|
||||||
|
assert not log_has('Parameter --enable-position-stacking detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
assert 'refresh_pairs' not in config
|
||||||
|
assert not log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
assert 'timerange' not in config
|
||||||
|
assert 'runmode' in config
|
||||||
|
assert config['runmode'] == RunMode.HYPEROPT
|
||||||
|
|
||||||
|
|
||||||
|
def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplog) -> None:
|
||||||
|
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
|
||||||
|
read_data=json.dumps(default_conf)
|
||||||
|
))
|
||||||
|
mocker.patch('freqtrade.configuration.Configuration._create_datadir', lambda s, c, x: x)
|
||||||
|
|
||||||
|
args = [
|
||||||
|
'--config', 'config.json',
|
||||||
|
'--datadir', '/foo/bar',
|
||||||
|
'hyperopt',
|
||||||
|
'--ticker-interval', '1m',
|
||||||
|
'--timerange', ':100',
|
||||||
|
'--refresh-pairs-cached',
|
||||||
|
'--enable-position-stacking',
|
||||||
|
'--disable-max-market-positions',
|
||||||
|
'--epochs', '1000',
|
||||||
|
'--spaces', 'all',
|
||||||
|
'--print-all'
|
||||||
|
]
|
||||||
|
|
||||||
|
config = setup_configuration(get_args(args))
|
||||||
|
assert 'max_open_trades' in config
|
||||||
|
assert 'stake_currency' in config
|
||||||
|
assert 'stake_amount' in config
|
||||||
|
assert 'exchange' in config
|
||||||
|
assert 'pair_whitelist' in config['exchange']
|
||||||
|
assert 'datadir' in config
|
||||||
|
assert config['runmode'] == RunMode.HYPEROPT
|
||||||
|
|
||||||
|
assert log_has(
|
||||||
|
'Using data folder: {} ...'.format(config['datadir']),
|
||||||
|
caplog.record_tuples
|
||||||
|
)
|
||||||
|
assert 'ticker_interval' in config
|
||||||
|
assert log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
||||||
|
assert log_has(
|
||||||
|
'Using ticker_interval: 1m ...',
|
||||||
|
caplog.record_tuples
|
||||||
|
)
|
||||||
|
|
||||||
|
assert 'position_stacking' in config
|
||||||
|
assert log_has('Parameter --enable-position-stacking detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
assert 'use_max_market_positions' in config
|
||||||
|
assert log_has('Parameter --disable-max-market-positions detected ...', caplog.record_tuples)
|
||||||
|
assert log_has('max_open_trades set to unlimited ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
assert 'refresh_pairs' in config
|
||||||
|
assert log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
assert 'timerange' in config
|
||||||
|
assert log_has(
|
||||||
|
'Parameter --timerange detected: {} ...'.format(config['timerange']),
|
||||||
|
caplog.record_tuples
|
||||||
|
)
|
||||||
|
|
||||||
|
assert 'epochs' in config
|
||||||
|
assert log_has('Parameter --epochs detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
assert 'spaces' in config
|
||||||
|
assert log_has(
|
||||||
|
'Parameter -s/--spaces detected: {}'.format(config['spaces']),
|
||||||
|
caplog.record_tuples
|
||||||
|
)
|
||||||
|
assert 'print_all' in config
|
||||||
|
assert log_has('Parameter --print-all detected: True', caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
|
def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
|
||||||
|
|
||||||
mocker.patch(
|
mocker.patch(
|
||||||
@ -72,7 +181,6 @@ def test_start(mocker, default_conf, caplog) -> None:
|
|||||||
|
|
||||||
args = [
|
args = [
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
|
||||||
'hyperopt',
|
'hyperopt',
|
||||||
'--epochs', '5'
|
'--epochs', '5'
|
||||||
]
|
]
|
||||||
@ -107,7 +215,7 @@ def test_start_failure(mocker, default_conf, caplog) -> None:
|
|||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
StrategyResolver({'strategy': 'DefaultStrategy'})
|
StrategyResolver({'strategy': 'DefaultStrategy'})
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(DependencyException):
|
||||||
start(args)
|
start(args)
|
||||||
assert log_has(
|
assert log_has(
|
||||||
"Please don't use --strategy for hyperopt.",
|
"Please don't use --strategy for hyperopt.",
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
ccxt==1.18.485
|
ccxt==1.18.486
|
||||||
SQLAlchemy==1.3.3
|
SQLAlchemy==1.3.3
|
||||||
python-telegram-bot==11.1.0
|
python-telegram-bot==11.1.0
|
||||||
arrow==0.13.1
|
arrow==0.13.1
|
||||||
cachetools==3.1.0
|
cachetools==3.1.0
|
||||||
requests==2.21.0
|
requests==2.21.0
|
||||||
urllib3==1.24.2
|
urllib3==1.25
|
||||||
wrapt==1.11.1
|
wrapt==1.11.1
|
||||||
scikit-learn==0.20.3
|
scikit-learn==0.20.3
|
||||||
joblib==0.13.2
|
joblib==0.13.2
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
ccxt==1.18.485
|
ccxt==1.18.486
|
||||||
SQLAlchemy==1.3.3
|
SQLAlchemy==1.3.3
|
||||||
python-telegram-bot==11.1.0
|
python-telegram-bot==11.1.0
|
||||||
arrow==0.13.1
|
arrow==0.13.1
|
||||||
cachetools==3.1.0
|
cachetools==3.1.0
|
||||||
requests==2.21.0
|
requests==2.21.0
|
||||||
urllib3==1.24.2
|
urllib3==1.25
|
||||||
wrapt==1.11.1
|
wrapt==1.11.1
|
||||||
numpy==1.16.3
|
numpy==1.16.3
|
||||||
pandas==0.24.2
|
pandas==0.24.2
|
||||||
|
Loading…
Reference in New Issue
Block a user