Merge pull request #1879 from freqtrade/refactor_optimize__init__
Speed up startup time
This commit is contained in:
commit
4fed263885
@ -340,25 +340,25 @@ class Arguments(object):
|
|||||||
Builds and attaches all subcommands
|
Builds and attaches all subcommands
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
from freqtrade.optimize import backtesting, hyperopt, edge_cli
|
from freqtrade.optimize import start_backtesting, start_hyperopt, start_edge
|
||||||
|
|
||||||
subparsers = self.parser.add_subparsers(dest='subparser')
|
subparsers = self.parser.add_subparsers(dest='subparser')
|
||||||
|
|
||||||
# Add backtesting subcommand
|
# Add backtesting subcommand
|
||||||
backtesting_cmd = subparsers.add_parser('backtesting', help='Backtesting module.')
|
backtesting_cmd = subparsers.add_parser('backtesting', help='Backtesting module.')
|
||||||
backtesting_cmd.set_defaults(func=backtesting.start)
|
backtesting_cmd.set_defaults(func=start_backtesting)
|
||||||
self.optimizer_shared_options(backtesting_cmd)
|
self.optimizer_shared_options(backtesting_cmd)
|
||||||
self.backtesting_options(backtesting_cmd)
|
self.backtesting_options(backtesting_cmd)
|
||||||
|
|
||||||
# Add edge subcommand
|
# Add edge subcommand
|
||||||
edge_cmd = subparsers.add_parser('edge', help='Edge module.')
|
edge_cmd = subparsers.add_parser('edge', help='Edge module.')
|
||||||
edge_cmd.set_defaults(func=edge_cli.start)
|
edge_cmd.set_defaults(func=start_edge)
|
||||||
self.optimizer_shared_options(edge_cmd)
|
self.optimizer_shared_options(edge_cmd)
|
||||||
self.edge_options(edge_cmd)
|
self.edge_options(edge_cmd)
|
||||||
|
|
||||||
# Add hyperopt subcommand
|
# Add hyperopt subcommand
|
||||||
hyperopt_cmd = subparsers.add_parser('hyperopt', help='Hyperopt module.')
|
hyperopt_cmd = subparsers.add_parser('hyperopt', help='Hyperopt module.')
|
||||||
hyperopt_cmd.set_defaults(func=hyperopt.start)
|
hyperopt_cmd.set_defaults(func=start_hyperopt)
|
||||||
self.optimizer_shared_options(hyperopt_cmd)
|
self.optimizer_shared_options(hyperopt_cmd)
|
||||||
self.hyperopt_options(hyperopt_cmd)
|
self.hyperopt_options(hyperopt_cmd)
|
||||||
|
|
||||||
|
@ -5,19 +5,21 @@ Includes:
|
|||||||
* load data for a pair (or a list of pairs) from disk
|
* load data for a pair (or a list of pairs) from disk
|
||||||
* download data from exchange and store to disk
|
* download data from exchange and store to disk
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import operator
|
||||||
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, List, Dict, Tuple, Any
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
from freqtrade import misc, OperationalException
|
from freqtrade import OperationalException, misc
|
||||||
from freqtrade.arguments import TimeRange
|
from freqtrade.arguments import TimeRange
|
||||||
from freqtrade.data.converter import parse_ticker_dataframe
|
from freqtrade.data.converter import parse_ticker_dataframe
|
||||||
from freqtrade.exchange import Exchange, timeframe_to_minutes
|
from freqtrade.exchange import Exchange, timeframe_to_minutes
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -243,3 +245,39 @@ def download_pair_history(datadir: Optional[Path],
|
|||||||
f'Error: {e}'
|
f'Error: {e}'
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_timeframe(data: Dict[str, DataFrame]) -> Tuple[arrow.Arrow, arrow.Arrow]:
|
||||||
|
"""
|
||||||
|
Get the maximum timeframe for the given backtest data
|
||||||
|
:param data: dictionary with preprocessed backtesting data
|
||||||
|
:return: tuple containing min_date, max_date
|
||||||
|
"""
|
||||||
|
timeframe = [
|
||||||
|
(arrow.get(frame['date'].min()), arrow.get(frame['date'].max()))
|
||||||
|
for frame in data.values()
|
||||||
|
]
|
||||||
|
return min(timeframe, key=operator.itemgetter(0))[0], \
|
||||||
|
max(timeframe, key=operator.itemgetter(1))[1]
|
||||||
|
|
||||||
|
|
||||||
|
def validate_backtest_data(data: Dict[str, DataFrame], min_date: datetime,
|
||||||
|
max_date: datetime, ticker_interval_mins: int) -> bool:
|
||||||
|
"""
|
||||||
|
Validates preprocessed backtesting data for missing values and shows warnings about it that.
|
||||||
|
|
||||||
|
:param data: dictionary with preprocessed backtesting data
|
||||||
|
:param min_date: start-date of the data
|
||||||
|
:param max_date: end-date of the data
|
||||||
|
:param ticker_interval_mins: ticker interval in minutes
|
||||||
|
"""
|
||||||
|
# total difference in minutes / interval-minutes
|
||||||
|
expected_frames = int((max_date - min_date).total_seconds() // 60 // ticker_interval_mins)
|
||||||
|
found_missing = False
|
||||||
|
for pair, df in data.items():
|
||||||
|
dflen = len(df)
|
||||||
|
if dflen < expected_frames:
|
||||||
|
found_missing = True
|
||||||
|
logger.warning("%s has missing frames: expected %s, got %s, that's %s missing values",
|
||||||
|
pair, expected_frames, dflen, expected_frames - dflen)
|
||||||
|
return found_missing
|
||||||
|
@ -13,7 +13,6 @@ from freqtrade import constants, OperationalException
|
|||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.arguments import TimeRange
|
from freqtrade.arguments import TimeRange
|
||||||
from freqtrade.data import history
|
from freqtrade.data import history
|
||||||
from freqtrade.optimize import get_timeframe
|
|
||||||
from freqtrade.strategy.interface import SellType
|
from freqtrade.strategy.interface import SellType
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +48,6 @@ class Edge():
|
|||||||
self.strategy = strategy
|
self.strategy = strategy
|
||||||
self.ticker_interval = self.strategy.ticker_interval
|
self.ticker_interval = self.strategy.ticker_interval
|
||||||
self.tickerdata_to_dataframe = self.strategy.tickerdata_to_dataframe
|
self.tickerdata_to_dataframe = self.strategy.tickerdata_to_dataframe
|
||||||
self.get_timeframe = get_timeframe
|
|
||||||
self.advise_sell = self.strategy.advise_sell
|
self.advise_sell = self.strategy.advise_sell
|
||||||
self.advise_buy = self.strategy.advise_buy
|
self.advise_buy = self.strategy.advise_buy
|
||||||
|
|
||||||
@ -117,7 +115,7 @@ class Edge():
|
|||||||
preprocessed = self.tickerdata_to_dataframe(data)
|
preprocessed = self.tickerdata_to_dataframe(data)
|
||||||
|
|
||||||
# Print timeframe
|
# Print timeframe
|
||||||
min_date, max_date = self.get_timeframe(preprocessed)
|
min_date, max_date = history.get_timeframe(preprocessed)
|
||||||
logger.info(
|
logger.info(
|
||||||
'Measuring data from %s up to %s (%s days) ...',
|
'Measuring data from %s up to %s (%s days) ...',
|
||||||
min_date.isoformat(),
|
min_date.isoformat(),
|
||||||
|
@ -1,49 +1,115 @@
|
|||||||
# pragma pylint: disable=missing-docstring
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from argparse import Namespace
|
||||||
from typing import Dict, Tuple
|
from typing import Any, Dict
|
||||||
import operator
|
|
||||||
|
|
||||||
import arrow
|
from filelock import FileLock, Timeout
|
||||||
from pandas import DataFrame
|
|
||||||
|
|
||||||
from freqtrade.optimize.default_hyperopt import DefaultHyperOpts # noqa: F401
|
from freqtrade import DependencyException, constants
|
||||||
|
from freqtrade.configuration import Configuration
|
||||||
|
from freqtrade.state import RunMode
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_timeframe(data: Dict[str, DataFrame]) -> Tuple[arrow.Arrow, arrow.Arrow]:
|
def setup_configuration(args: Namespace, method: RunMode) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Get the maximum timeframe for the given backtest data
|
Prepare the configuration for the Hyperopt module
|
||||||
:param data: dictionary with preprocessed backtesting data
|
:param args: Cli args from Arguments()
|
||||||
:return: tuple containing min_date, max_date
|
:return: Configuration
|
||||||
"""
|
"""
|
||||||
timeframe = [
|
configuration = Configuration(args, method)
|
||||||
(arrow.get(frame['date'].min()), arrow.get(frame['date'].max()))
|
config = configuration.load_config()
|
||||||
for frame in data.values()
|
|
||||||
]
|
# Ensure we do not use Exchange credentials
|
||||||
return min(timeframe, key=operator.itemgetter(0))[0], \
|
config['exchange']['key'] = ''
|
||||||
max(timeframe, key=operator.itemgetter(1))[1]
|
config['exchange']['secret'] = ''
|
||||||
|
|
||||||
|
if method == RunMode.BACKTEST:
|
||||||
|
if config['stake_amount'] == constants.UNLIMITED_STAKE_AMOUNT:
|
||||||
|
raise DependencyException('stake amount could not be "%s" for backtesting' %
|
||||||
|
constants.UNLIMITED_STAKE_AMOUNT)
|
||||||
|
|
||||||
|
if method == RunMode.HYPEROPT:
|
||||||
|
# Special cases for Hyperopt
|
||||||
|
if config.get('strategy') and config.get('strategy') != 'DefaultStrategy':
|
||||||
|
logger.error("Please don't use --strategy for hyperopt.")
|
||||||
|
logger.error(
|
||||||
|
"Read the documentation at "
|
||||||
|
"https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md "
|
||||||
|
"to understand how to configure hyperopt.")
|
||||||
|
raise DependencyException("--strategy configured but not supported for hyperopt")
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
def validate_backtest_data(data: Dict[str, DataFrame], min_date: datetime,
|
def start_backtesting(args: Namespace) -> None:
|
||||||
max_date: datetime, ticker_interval_mins: int) -> bool:
|
|
||||||
"""
|
"""
|
||||||
Validates preprocessed backtesting data for missing values and shows warnings about it that.
|
Start Backtesting script
|
||||||
|
:param args: Cli args from Arguments()
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
# Import here to avoid loading backtesting module when it's not used
|
||||||
|
from freqtrade.optimize.backtesting import Backtesting
|
||||||
|
|
||||||
:param data: dictionary with preprocessed backtesting data
|
# Initialize configuration
|
||||||
:param min_date: start-date of the data
|
config = setup_configuration(args, RunMode.BACKTEST)
|
||||||
:param max_date: end-date of the data
|
|
||||||
:param ticker_interval_mins: ticker interval in minutes
|
logger.info('Starting freqtrade in Backtesting mode')
|
||||||
|
|
||||||
|
# Initialize backtesting object
|
||||||
|
backtesting = Backtesting(config)
|
||||||
|
backtesting.start()
|
||||||
|
|
||||||
|
|
||||||
|
def start_hyperopt(args: Namespace) -> None:
|
||||||
"""
|
"""
|
||||||
# total difference in minutes / interval-minutes
|
Start hyperopt script
|
||||||
expected_frames = int((max_date - min_date).total_seconds() // 60 // ticker_interval_mins)
|
:param args: Cli args from Arguments()
|
||||||
found_missing = False
|
:return: None
|
||||||
for pair, df in data.items():
|
"""
|
||||||
dflen = len(df)
|
# Import here to avoid loading hyperopt module when it's not used
|
||||||
if dflen < expected_frames:
|
from freqtrade.optimize.hyperopt import Hyperopt, HYPEROPT_LOCKFILE
|
||||||
found_missing = True
|
|
||||||
logger.warning("%s has missing frames: expected %s, got %s, that's %s missing values",
|
# Initialize configuration
|
||||||
pair, expected_frames, dflen, expected_frames - dflen)
|
config = setup_configuration(args, RunMode.HYPEROPT)
|
||||||
return found_missing
|
|
||||||
|
logger.info('Starting freqtrade in Hyperopt mode')
|
||||||
|
|
||||||
|
lock = FileLock(HYPEROPT_LOCKFILE)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with lock.acquire(timeout=1):
|
||||||
|
|
||||||
|
# Remove noisy log messages
|
||||||
|
logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING)
|
||||||
|
logging.getLogger('filelock').setLevel(logging.WARNING)
|
||||||
|
|
||||||
|
# Initialize backtesting object
|
||||||
|
hyperopt = Hyperopt(config)
|
||||||
|
hyperopt.start()
|
||||||
|
|
||||||
|
except Timeout:
|
||||||
|
logger.info("Another running instance of freqtrade Hyperopt detected.")
|
||||||
|
logger.info("Simultaneous execution of multiple Hyperopt commands is not supported. "
|
||||||
|
"Hyperopt module is resource hungry. Please run your Hyperopts sequentially "
|
||||||
|
"or on separate machines.")
|
||||||
|
logger.info("Quitting now.")
|
||||||
|
# TODO: return False here in order to help freqtrade to exit
|
||||||
|
# with non-zero exit code...
|
||||||
|
# Same in Edge and Backtesting start() functions.
|
||||||
|
|
||||||
|
|
||||||
|
def start_edge(args: Namespace) -> None:
|
||||||
|
"""
|
||||||
|
Start Edge script
|
||||||
|
:param args: Cli args from Arguments()
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
from freqtrade.optimize.edge_cli import EdgeCli
|
||||||
|
# Initialize configuration
|
||||||
|
config = setup_configuration(args, RunMode.EDGE)
|
||||||
|
logger.info('Starting freqtrade in Edge mode')
|
||||||
|
|
||||||
|
# Initialize Edge object
|
||||||
|
edge_cli = EdgeCli(config)
|
||||||
|
edge_cli.start()
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
This module contains the backtesting logic
|
This module contains the backtesting logic
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
from argparse import Namespace
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -13,10 +12,7 @@ from typing import Any, Dict, List, NamedTuple, Optional
|
|||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
from freqtrade import optimize
|
|
||||||
from freqtrade import DependencyException, constants
|
|
||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.configuration import Configuration
|
|
||||||
from freqtrade.data import history
|
from freqtrade.data import history
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
from freqtrade.data.dataprovider import DataProvider
|
||||||
from freqtrade.exchange import timeframe_to_minutes
|
from freqtrade.exchange import timeframe_to_minutes
|
||||||
@ -24,8 +20,7 @@ from freqtrade.misc import file_dump_json
|
|||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
|
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
from freqtrade.strategy.interface import SellType, IStrategy
|
from freqtrade.strategy.interface import IStrategy, SellType
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -440,9 +435,9 @@ class Backtesting(object):
|
|||||||
logger.info("Running backtesting for Strategy %s", strat.get_strategy_name())
|
logger.info("Running backtesting for Strategy %s", strat.get_strategy_name())
|
||||||
self._set_strategy(strat)
|
self._set_strategy(strat)
|
||||||
|
|
||||||
min_date, max_date = optimize.get_timeframe(data)
|
min_date, max_date = history.get_timeframe(data)
|
||||||
# Validate dataframe for missing values (mainly at start and end, as fillup is called)
|
# Validate dataframe for missing values (mainly at start and end, as fillup is called)
|
||||||
optimize.validate_backtest_data(data, min_date, max_date,
|
history.validate_backtest_data(data, min_date, max_date,
|
||||||
timeframe_to_minutes(self.ticker_interval))
|
timeframe_to_minutes(self.ticker_interval))
|
||||||
logger.info(
|
logger.info(
|
||||||
'Backtesting with data from %s up to %s (%s days)..',
|
'Backtesting with data from %s up to %s (%s days)..',
|
||||||
@ -486,39 +481,3 @@ class Backtesting(object):
|
|||||||
print(' Strategy Summary '.center(133, '='))
|
print(' Strategy Summary '.center(133, '='))
|
||||||
print(self._generate_text_table_strategy(all_results))
|
print(self._generate_text_table_strategy(all_results))
|
||||||
print('\nFor more details, please look at the detail tables above')
|
print('\nFor more details, please look at the detail tables above')
|
||||||
|
|
||||||
|
|
||||||
def setup_configuration(args: Namespace) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
Prepare the configuration for the backtesting
|
|
||||||
:param args: Cli args from Arguments()
|
|
||||||
:return: Configuration
|
|
||||||
"""
|
|
||||||
configuration = Configuration(args, RunMode.BACKTEST)
|
|
||||||
config = configuration.get_config()
|
|
||||||
|
|
||||||
# Ensure we do not use Exchange credentials
|
|
||||||
config['exchange']['key'] = ''
|
|
||||||
config['exchange']['secret'] = ''
|
|
||||||
|
|
||||||
if config['stake_amount'] == constants.UNLIMITED_STAKE_AMOUNT:
|
|
||||||
raise DependencyException('stake amount could not be "%s" for backtesting' %
|
|
||||||
constants.UNLIMITED_STAKE_AMOUNT)
|
|
||||||
|
|
||||||
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 Backtesting mode')
|
|
||||||
|
|
||||||
# Initialize backtesting object
|
|
||||||
backtesting = Backtesting(config)
|
|
||||||
backtesting.start()
|
|
||||||
|
@ -4,16 +4,13 @@
|
|||||||
This module contains the edge backtesting interface
|
This module contains the edge backtesting interface
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
from argparse import Namespace
|
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
from freqtrade.edge import Edge
|
from freqtrade.edge import Edge
|
||||||
|
|
||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.configuration import Configuration
|
|
||||||
from freqtrade.exchange import Exchange
|
from freqtrade.exchange import Exchange
|
||||||
from freqtrade.resolvers import StrategyResolver
|
from freqtrade.resolvers import StrategyResolver
|
||||||
from freqtrade.state import RunMode
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -77,34 +74,3 @@ class EdgeCli(object):
|
|||||||
if result:
|
if result:
|
||||||
print('') # blank line for readability
|
print('') # blank line for readability
|
||||||
print(self._generate_edge_table(self.edge._cached_pairs))
|
print(self._generate_edge_table(self.edge._cached_pairs))
|
||||||
|
|
||||||
|
|
||||||
def setup_configuration(args: Namespace) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
Prepare the configuration for edge backtesting
|
|
||||||
:param args: Cli args from Arguments()
|
|
||||||
:return: Configuration
|
|
||||||
"""
|
|
||||||
configuration = Configuration(args, RunMode.EDGECLI)
|
|
||||||
config = configuration.get_config()
|
|
||||||
|
|
||||||
# Ensure we do not use Exchange credentials
|
|
||||||
config['exchange']['key'] = ''
|
|
||||||
config['exchange']['secret'] = ''
|
|
||||||
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
def start(args: Namespace) -> None:
|
|
||||||
"""
|
|
||||||
Start Edge script
|
|
||||||
:param args: Cli args from Arguments()
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
# Initialize configuration
|
|
||||||
config = setup_configuration(args)
|
|
||||||
logger.info('Starting freqtrade in Edge mode')
|
|
||||||
|
|
||||||
# Initialize Edge object
|
|
||||||
edge_cli = EdgeCli(config)
|
|
||||||
edge_cli.start()
|
|
||||||
|
@ -7,28 +7,22 @@ This module contains the hyperopt logic
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from argparse import Namespace
|
|
||||||
from math import exp
|
from math import exp
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
from filelock import Timeout, FileLock
|
|
||||||
from joblib import Parallel, delayed, dump, load, wrap_non_picklable_objects, cpu_count
|
from joblib import Parallel, delayed, dump, load, wrap_non_picklable_objects, cpu_count
|
||||||
from pandas import DataFrame
|
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.data.history import load_data, get_timeframe, validate_backtest_data
|
||||||
from freqtrade.data.history import load_data
|
|
||||||
from freqtrade.exchange import timeframe_to_minutes
|
from freqtrade.exchange import timeframe_to_minutes
|
||||||
from freqtrade.optimize import get_timeframe, validate_backtest_data
|
|
||||||
from freqtrade.optimize.backtesting import Backtesting
|
from freqtrade.optimize.backtesting import Backtesting
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver
|
||||||
from freqtrade.resolvers import HyperOptResolver
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -343,62 +337,3 @@ class Hyperopt(Backtesting):
|
|||||||
|
|
||||||
self.save_trials()
|
self.save_trials()
|
||||||
self.log_trials_result()
|
self.log_trials_result()
|
||||||
|
|
||||||
|
|
||||||
def setup_configuration(args: Namespace) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
Prepare the configuration for the Hyperopt module
|
|
||||||
:param args: Cli args from Arguments()
|
|
||||||
:return: Configuration
|
|
||||||
"""
|
|
||||||
configuration = Configuration(args, RunMode.HYPEROPT)
|
|
||||||
config = configuration.load_config()
|
|
||||||
|
|
||||||
# Ensure we do not use Exchange credentials
|
|
||||||
config['exchange']['key'] = ''
|
|
||||||
config['exchange']['secret'] = ''
|
|
||||||
|
|
||||||
if config.get('strategy') and config.get('strategy') != 'DefaultStrategy':
|
|
||||||
logger.error("Please don't use --strategy for hyperopt.")
|
|
||||||
logger.error(
|
|
||||||
"Read the documentation at "
|
|
||||||
"https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md "
|
|
||||||
"to understand how to configure 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')
|
|
||||||
|
|
||||||
lock = FileLock(HYPEROPT_LOCKFILE)
|
|
||||||
|
|
||||||
try:
|
|
||||||
with lock.acquire(timeout=1):
|
|
||||||
|
|
||||||
# Remove noisy log messages
|
|
||||||
logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING)
|
|
||||||
logging.getLogger('filelock').setLevel(logging.WARNING)
|
|
||||||
|
|
||||||
# Initialize backtesting object
|
|
||||||
hyperopt = Hyperopt(config)
|
|
||||||
hyperopt.start()
|
|
||||||
|
|
||||||
except Timeout:
|
|
||||||
logger.info("Another running instance of freqtrade Hyperopt detected.")
|
|
||||||
logger.info("Simultaneous execution of multiple Hyperopt commands is not supported. "
|
|
||||||
"Hyperopt module is resource hungry. Please run your Hyperopts sequentially "
|
|
||||||
"or on separate machines.")
|
|
||||||
logger.info("Quitting now.")
|
|
||||||
# TODO: return False here in order to help freqtrade to exit
|
|
||||||
# with non-zero exit code...
|
|
||||||
# Same in Edge and Backtesting start() functions.
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from freqtrade.resolvers.iresolver import IResolver # noqa: F401
|
from freqtrade.resolvers.iresolver import IResolver # noqa: F401
|
||||||
from freqtrade.resolvers.exchange_resolver import ExchangeResolver # noqa: F401
|
from freqtrade.resolvers.exchange_resolver import ExchangeResolver # noqa: F401
|
||||||
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver # noqa: F401
|
# Don't import HyperoptResolver to avoid loading the whole Optimize tree
|
||||||
|
# from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver # noqa: F401
|
||||||
from freqtrade.resolvers.pairlist_resolver import PairListResolver # noqa: F401
|
from freqtrade.resolvers.pairlist_resolver import PairListResolver # noqa: F401
|
||||||
from freqtrade.resolvers.strategy_resolver import StrategyResolver # noqa: F401
|
from freqtrade.resolvers.strategy_resolver import StrategyResolver # noqa: F401
|
||||||
|
@ -18,11 +18,11 @@ class State(Enum):
|
|||||||
class RunMode(Enum):
|
class RunMode(Enum):
|
||||||
"""
|
"""
|
||||||
Bot running mode (backtest, hyperopt, ...)
|
Bot running mode (backtest, hyperopt, ...)
|
||||||
can be "live", "dry-run", "backtest", "edgecli", "hyperopt".
|
can be "live", "dry-run", "backtest", "edge", "hyperopt".
|
||||||
"""
|
"""
|
||||||
LIVE = "live"
|
LIVE = "live"
|
||||||
DRY_RUN = "dry_run"
|
DRY_RUN = "dry_run"
|
||||||
BACKTEST = "backtest"
|
BACKTEST = "backtest"
|
||||||
EDGECLI = "edgecli"
|
EDGE = "edge"
|
||||||
HYPEROPT = "hyperopt"
|
HYPEROPT = "hyperopt"
|
||||||
OTHER = "other" # Used for plotting scripts and test
|
OTHER = "other" # Used for plotting scripts and test
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from freqtrade.data.converter import parse_ticker_dataframe, ohlcv_fill_up_missing_data
|
from freqtrade.data.converter import parse_ticker_dataframe, ohlcv_fill_up_missing_data
|
||||||
from freqtrade.data.history import load_pair_history
|
from freqtrade.data.history import load_pair_history, validate_backtest_data, get_timeframe
|
||||||
from freqtrade.optimize import validate_backtest_data, get_timeframe
|
|
||||||
from freqtrade.tests.conftest import log_has
|
from freqtrade.tests.conftest import log_has
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,24 +2,25 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
|
||||||
import uuid
|
import uuid
|
||||||
|
from pathlib import Path
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
from pandas import DataFrame
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from pandas import DataFrame
|
||||||
|
|
||||||
from freqtrade import OperationalException
|
from freqtrade import OperationalException
|
||||||
from freqtrade.arguments import TimeRange
|
from freqtrade.arguments import TimeRange
|
||||||
from freqtrade.data import history
|
from freqtrade.data import history
|
||||||
from freqtrade.data.history import (download_pair_history,
|
from freqtrade.data.history import (download_pair_history,
|
||||||
load_cached_data_for_updating,
|
load_cached_data_for_updating,
|
||||||
load_tickerdata_file,
|
load_tickerdata_file, make_testdata_path,
|
||||||
make_testdata_path,
|
|
||||||
trim_tickerlist)
|
trim_tickerlist)
|
||||||
|
from freqtrade.exchange import timeframe_to_minutes
|
||||||
from freqtrade.misc import file_dump_json
|
from freqtrade.misc import file_dump_json
|
||||||
from freqtrade.tests.conftest import get_patched_exchange, log_has
|
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||||
|
from freqtrade.tests.conftest import get_patched_exchange, log_has, patch_exchange
|
||||||
|
|
||||||
# Change this if modifying UNITTEST/BTC testdatafile
|
# Change this if modifying UNITTEST/BTC testdatafile
|
||||||
_BTC_UNITTEST_LENGTH = 13681
|
_BTC_UNITTEST_LENGTH = 13681
|
||||||
@ -495,3 +496,62 @@ def test_file_dump_json_tofile() -> None:
|
|||||||
|
|
||||||
# Remove the file
|
# Remove the file
|
||||||
_clean_test_file(file)
|
_clean_test_file(file)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_timeframe(default_conf, mocker) -> None:
|
||||||
|
patch_exchange(mocker)
|
||||||
|
strategy = DefaultStrategy(default_conf)
|
||||||
|
|
||||||
|
data = strategy.tickerdata_to_dataframe(
|
||||||
|
history.load_data(
|
||||||
|
datadir=None,
|
||||||
|
ticker_interval='1m',
|
||||||
|
pairs=['UNITTEST/BTC']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
min_date, max_date = history.get_timeframe(data)
|
||||||
|
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
|
||||||
|
assert max_date.isoformat() == '2017-11-14T22:58:00+00:00'
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_backtest_data_warn(default_conf, mocker, caplog) -> None:
|
||||||
|
patch_exchange(mocker)
|
||||||
|
strategy = DefaultStrategy(default_conf)
|
||||||
|
|
||||||
|
data = strategy.tickerdata_to_dataframe(
|
||||||
|
history.load_data(
|
||||||
|
datadir=None,
|
||||||
|
ticker_interval='1m',
|
||||||
|
pairs=['UNITTEST/BTC'],
|
||||||
|
fill_up_missing=False
|
||||||
|
)
|
||||||
|
)
|
||||||
|
min_date, max_date = history.get_timeframe(data)
|
||||||
|
caplog.clear()
|
||||||
|
assert history.validate_backtest_data(data, min_date, max_date,
|
||||||
|
timeframe_to_minutes('1m'))
|
||||||
|
assert len(caplog.record_tuples) == 1
|
||||||
|
assert log_has(
|
||||||
|
"UNITTEST/BTC has missing frames: expected 14396, got 13680, that's 716 missing values",
|
||||||
|
caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_backtest_data(default_conf, mocker, caplog) -> None:
|
||||||
|
patch_exchange(mocker)
|
||||||
|
strategy = DefaultStrategy(default_conf)
|
||||||
|
|
||||||
|
timerange = TimeRange('index', 'index', 200, 250)
|
||||||
|
data = strategy.tickerdata_to_dataframe(
|
||||||
|
history.load_data(
|
||||||
|
datadir=None,
|
||||||
|
ticker_interval='5m',
|
||||||
|
pairs=['UNITTEST/BTC'],
|
||||||
|
timerange=timerange
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
min_date, max_date = history.get_timeframe(data)
|
||||||
|
caplog.clear()
|
||||||
|
assert not history.validate_backtest_data(data, min_date, max_date,
|
||||||
|
timeframe_to_minutes('5m'))
|
||||||
|
assert len(caplog.record_tuples) == 0
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
import logging
|
import logging
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pandas import DataFrame
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from pandas import DataFrame
|
||||||
|
|
||||||
|
from freqtrade.data.history import get_timeframe
|
||||||
from freqtrade.optimize import get_timeframe
|
|
||||||
from freqtrade.optimize.backtesting import Backtesting
|
from freqtrade.optimize.backtesting import Backtesting
|
||||||
from freqtrade.strategy.interface import SellType
|
from freqtrade.strategy.interface import SellType
|
||||||
from freqtrade.tests.optimize import (BTrade, BTContainer, _build_backtest_dataframe,
|
|
||||||
_get_frame_time_from_offset, tests_ticker_interval)
|
|
||||||
from freqtrade.tests.conftest import patch_exchange
|
from freqtrade.tests.conftest import patch_exchange
|
||||||
|
from freqtrade.tests.optimize import (BTContainer, BTrade,
|
||||||
|
_build_backtest_dataframe,
|
||||||
|
_get_frame_time_from_offset,
|
||||||
|
tests_ticker_interval)
|
||||||
|
|
||||||
# Test 1 Minus 8% Close
|
# Test 1 Minus 8% Close
|
||||||
# Test with Stop-loss at 1%
|
# Test with Stop-loss at 1%
|
||||||
|
@ -17,9 +17,9 @@ from freqtrade.data import history
|
|||||||
from freqtrade.data.btanalysis import evaluate_result_multi
|
from freqtrade.data.btanalysis import evaluate_result_multi
|
||||||
from freqtrade.data.converter import parse_ticker_dataframe
|
from freqtrade.data.converter import parse_ticker_dataframe
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
from freqtrade.data.dataprovider import DataProvider
|
||||||
from freqtrade.optimize import get_timeframe
|
from freqtrade.data.history import get_timeframe
|
||||||
from freqtrade.optimize.backtesting import (Backtesting, setup_configuration,
|
from freqtrade.optimize import setup_configuration, start_backtesting
|
||||||
start)
|
from freqtrade.optimize.backtesting import Backtesting
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||||
from freqtrade.strategy.interface import SellType
|
from freqtrade.strategy.interface import SellType
|
||||||
@ -178,7 +178,7 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
|||||||
'backtesting'
|
'backtesting'
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_configuration(get_args(args))
|
config = setup_configuration(get_args(args), RunMode.BACKTEST)
|
||||||
assert 'max_open_trades' in config
|
assert 'max_open_trades' in config
|
||||||
assert 'stake_currency' in config
|
assert 'stake_currency' in config
|
||||||
assert 'stake_amount' in config
|
assert 'stake_amount' in config
|
||||||
@ -228,7 +228,7 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) ->
|
|||||||
'--export-filename', 'foo_bar.json'
|
'--export-filename', 'foo_bar.json'
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_configuration(get_args(args))
|
config = setup_configuration(get_args(args), RunMode.BACKTEST)
|
||||||
assert 'max_open_trades' in config
|
assert 'max_open_trades' in config
|
||||||
assert 'stake_currency' in config
|
assert 'stake_currency' in config
|
||||||
assert 'stake_amount' in config
|
assert 'stake_amount' in config
|
||||||
@ -290,7 +290,7 @@ def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog
|
|||||||
]
|
]
|
||||||
|
|
||||||
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
||||||
setup_configuration(get_args(args))
|
setup_configuration(get_args(args), RunMode.BACKTEST)
|
||||||
|
|
||||||
|
|
||||||
def test_start(mocker, fee, default_conf, caplog) -> None:
|
def test_start(mocker, fee, default_conf, caplog) -> None:
|
||||||
@ -307,7 +307,7 @@ def test_start(mocker, fee, default_conf, caplog) -> None:
|
|||||||
'backtesting'
|
'backtesting'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
start(args)
|
start_backtesting(args)
|
||||||
assert log_has(
|
assert log_has(
|
||||||
'Starting freqtrade in Backtesting mode',
|
'Starting freqtrade in Backtesting mode',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
@ -472,7 +472,7 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None:
|
|||||||
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
|
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
|
||||||
|
|
||||||
mocker.patch('freqtrade.data.history.load_data', mocked_load_data)
|
mocker.patch('freqtrade.data.history.load_data', mocked_load_data)
|
||||||
mocker.patch('freqtrade.optimize.get_timeframe', get_timeframe)
|
mocker.patch('freqtrade.data.history.get_timeframe', get_timeframe)
|
||||||
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
|
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
@ -507,7 +507,7 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog) -> None:
|
|||||||
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
|
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
|
||||||
|
|
||||||
mocker.patch('freqtrade.data.history.load_data', MagicMock(return_value={}))
|
mocker.patch('freqtrade.data.history.load_data', MagicMock(return_value={}))
|
||||||
mocker.patch('freqtrade.optimize.get_timeframe', get_timeframe)
|
mocker.patch('freqtrade.data.history.get_timeframe', get_timeframe)
|
||||||
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
|
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
@ -847,7 +847,7 @@ def test_backtest_start_live(default_conf, mocker, caplog):
|
|||||||
'--disable-max-market-positions'
|
'--disable-max-market-positions'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
start(args)
|
start_backtesting(args)
|
||||||
# check the logs, that will contain the backtest result
|
# check the logs, that will contain the backtest result
|
||||||
exists = [
|
exists = [
|
||||||
'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
||||||
@ -901,7 +901,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog):
|
|||||||
'TestStrategy',
|
'TestStrategy',
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
start(args)
|
start_backtesting(args)
|
||||||
# 2 backtests, 4 tables
|
# 2 backtests, 4 tables
|
||||||
assert backtestmock.call_count == 2
|
assert backtestmock.call_count == 2
|
||||||
assert gen_table_mock.call_count == 4
|
assert gen_table_mock.call_count == 4
|
||||||
|
@ -7,7 +7,8 @@ from unittest.mock import MagicMock
|
|||||||
|
|
||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.edge import PairInfo
|
from freqtrade.edge import PairInfo
|
||||||
from freqtrade.optimize.edge_cli import EdgeCli, setup_configuration, start
|
from freqtrade.optimize import start_edge, setup_configuration
|
||||||
|
from freqtrade.optimize.edge_cli import EdgeCli
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
|
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
|
||||||
|
|
||||||
@ -27,8 +28,8 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
|||||||
'edge'
|
'edge'
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_configuration(get_args(args))
|
config = setup_configuration(get_args(args), RunMode.EDGE)
|
||||||
assert config['runmode'] == RunMode.EDGECLI
|
assert config['runmode'] == RunMode.EDGE
|
||||||
|
|
||||||
assert 'max_open_trades' in config
|
assert 'max_open_trades' in config
|
||||||
assert 'stake_currency' in config
|
assert 'stake_currency' in config
|
||||||
@ -67,14 +68,14 @@ def test_setup_edge_configuration_with_arguments(mocker, edge_conf, caplog) -> N
|
|||||||
'--stoplosses=-0.01,-0.10,-0.001'
|
'--stoplosses=-0.01,-0.10,-0.001'
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_configuration(get_args(args))
|
config = setup_configuration(get_args(args), RunMode.EDGE)
|
||||||
assert 'max_open_trades' in config
|
assert 'max_open_trades' in config
|
||||||
assert 'stake_currency' in config
|
assert 'stake_currency' in config
|
||||||
assert 'stake_amount' in config
|
assert 'stake_amount' in config
|
||||||
assert 'exchange' in config
|
assert 'exchange' in config
|
||||||
assert 'pair_whitelist' in config['exchange']
|
assert 'pair_whitelist' in config['exchange']
|
||||||
assert 'datadir' in config
|
assert 'datadir' in config
|
||||||
assert config['runmode'] == RunMode.EDGECLI
|
assert config['runmode'] == RunMode.EDGE
|
||||||
assert log_has(
|
assert log_has(
|
||||||
'Using data folder: {} ...'.format(config['datadir']),
|
'Using data folder: {} ...'.format(config['datadir']),
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
@ -106,7 +107,7 @@ def test_start(mocker, fee, edge_conf, caplog) -> None:
|
|||||||
'edge'
|
'edge'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
start(args)
|
start_edge(args)
|
||||||
assert log_has(
|
assert log_has(
|
||||||
'Starting freqtrade in Edge mode',
|
'Starting freqtrade in Edge mode',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
|
@ -3,6 +3,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
from filelock import Timeout
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import pytest
|
import pytest
|
||||||
@ -11,8 +12,9 @@ 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.default_hyperopt import DefaultHyperOpts
|
from freqtrade.optimize.default_hyperopt import DefaultHyperOpts
|
||||||
from freqtrade.optimize.hyperopt import Hyperopt, setup_configuration, start
|
from freqtrade.optimize.hyperopt import Hyperopt, HYPEROPT_LOCKFILE
|
||||||
from freqtrade.resolvers import HyperOptResolver
|
from freqtrade.optimize import setup_configuration, start_hyperopt
|
||||||
|
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
|
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
|
||||||
from freqtrade.tests.optimize.test_backtesting import get_args
|
from freqtrade.tests.optimize.test_backtesting import get_args
|
||||||
@ -52,7 +54,7 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca
|
|||||||
'hyperopt'
|
'hyperopt'
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_configuration(get_args(args))
|
config = setup_configuration(get_args(args), RunMode.HYPEROPT)
|
||||||
assert 'max_open_trades' in config
|
assert 'max_open_trades' in config
|
||||||
assert 'stake_currency' in config
|
assert 'stake_currency' in config
|
||||||
assert 'stake_amount' in config
|
assert 'stake_amount' in config
|
||||||
@ -100,7 +102,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
|
|||||||
'--print-all'
|
'--print-all'
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_configuration(get_args(args))
|
config = setup_configuration(get_args(args), RunMode.HYPEROPT)
|
||||||
assert 'max_open_trades' in config
|
assert 'max_open_trades' in config
|
||||||
assert 'stake_currency' in config
|
assert 'stake_currency' in config
|
||||||
assert 'stake_amount' in config
|
assert 'stake_amount' in config
|
||||||
@ -183,7 +185,7 @@ def test_start(mocker, default_conf, caplog) -> None:
|
|||||||
'--epochs', '5'
|
'--epochs', '5'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
start(args)
|
start_hyperopt(args)
|
||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
pprint.pprint(caplog.record_tuples)
|
pprint.pprint(caplog.record_tuples)
|
||||||
@ -214,7 +216,7 @@ def test_start_no_data(mocker, default_conf, caplog) -> None:
|
|||||||
'--epochs', '5'
|
'--epochs', '5'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
start(args)
|
start_hyperopt(args)
|
||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
pprint.pprint(caplog.record_tuples)
|
pprint.pprint(caplog.record_tuples)
|
||||||
@ -239,13 +241,35 @@ def test_start_failure(mocker, default_conf, caplog) -> None:
|
|||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
start(args)
|
start_hyperopt(args)
|
||||||
assert log_has(
|
assert log_has(
|
||||||
"Please don't use --strategy for hyperopt.",
|
"Please don't use --strategy for hyperopt.",
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_start_filelock(mocker, default_conf, caplog) -> None:
|
||||||
|
start_mock = MagicMock(side_effect=Timeout(HYPEROPT_LOCKFILE))
|
||||||
|
mocker.patch(
|
||||||
|
'freqtrade.configuration.Configuration._load_config_file',
|
||||||
|
lambda *args, **kwargs: default_conf
|
||||||
|
)
|
||||||
|
mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock)
|
||||||
|
patch_exchange(mocker)
|
||||||
|
|
||||||
|
args = [
|
||||||
|
'--config', 'config.json',
|
||||||
|
'hyperopt',
|
||||||
|
'--epochs', '5'
|
||||||
|
]
|
||||||
|
args = get_args(args)
|
||||||
|
start_hyperopt(args)
|
||||||
|
assert log_has(
|
||||||
|
"Another running instance of freqtrade Hyperopt detected.",
|
||||||
|
caplog.record_tuples
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_loss_calculation_prefer_correct_trade_count(hyperopt) -> None:
|
def test_loss_calculation_prefer_correct_trade_count(hyperopt) -> None:
|
||||||
|
|
||||||
correct = hyperopt.calculate_loss(1, hyperopt.target_trades, 20)
|
correct = hyperopt.calculate_loss(1, hyperopt.target_trades, 20)
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
# pragma pylint: disable=missing-docstring, protected-access, C0103
|
|
||||||
from freqtrade import optimize
|
|
||||||
from freqtrade.arguments import TimeRange
|
|
||||||
from freqtrade.data import history
|
|
||||||
from freqtrade.exchange import timeframe_to_minutes
|
|
||||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
|
||||||
from freqtrade.tests.conftest import log_has, patch_exchange
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_timeframe(default_conf, mocker) -> None:
|
|
||||||
patch_exchange(mocker)
|
|
||||||
strategy = DefaultStrategy(default_conf)
|
|
||||||
|
|
||||||
data = strategy.tickerdata_to_dataframe(
|
|
||||||
history.load_data(
|
|
||||||
datadir=None,
|
|
||||||
ticker_interval='1m',
|
|
||||||
pairs=['UNITTEST/BTC']
|
|
||||||
)
|
|
||||||
)
|
|
||||||
min_date, max_date = optimize.get_timeframe(data)
|
|
||||||
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
|
|
||||||
assert max_date.isoformat() == '2017-11-14T22:58:00+00:00'
|
|
||||||
|
|
||||||
|
|
||||||
def test_validate_backtest_data_warn(default_conf, mocker, caplog) -> None:
|
|
||||||
patch_exchange(mocker)
|
|
||||||
strategy = DefaultStrategy(default_conf)
|
|
||||||
|
|
||||||
data = strategy.tickerdata_to_dataframe(
|
|
||||||
history.load_data(
|
|
||||||
datadir=None,
|
|
||||||
ticker_interval='1m',
|
|
||||||
pairs=['UNITTEST/BTC'],
|
|
||||||
fill_up_missing=False
|
|
||||||
)
|
|
||||||
)
|
|
||||||
min_date, max_date = optimize.get_timeframe(data)
|
|
||||||
caplog.clear()
|
|
||||||
assert optimize.validate_backtest_data(data, min_date, max_date,
|
|
||||||
timeframe_to_minutes('1m'))
|
|
||||||
assert len(caplog.record_tuples) == 1
|
|
||||||
assert log_has(
|
|
||||||
"UNITTEST/BTC has missing frames: expected 14396, got 13680, that's 716 missing values",
|
|
||||||
caplog.record_tuples)
|
|
||||||
|
|
||||||
|
|
||||||
def test_validate_backtest_data(default_conf, mocker, caplog) -> None:
|
|
||||||
patch_exchange(mocker)
|
|
||||||
strategy = DefaultStrategy(default_conf)
|
|
||||||
|
|
||||||
timerange = TimeRange('index', 'index', 200, 250)
|
|
||||||
data = strategy.tickerdata_to_dataframe(
|
|
||||||
history.load_data(
|
|
||||||
datadir=None,
|
|
||||||
ticker_interval='5m',
|
|
||||||
pairs=['UNITTEST/BTC'],
|
|
||||||
timerange=timerange
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
min_date, max_date = optimize.get_timeframe(data)
|
|
||||||
caplog.clear()
|
|
||||||
assert not optimize.validate_backtest_data(data, min_date, max_date,
|
|
||||||
timeframe_to_minutes('5m'))
|
|
||||||
assert len(caplog.record_tuples) == 0
|
|
@ -19,7 +19,7 @@ def test_parse_args_backtesting(mocker) -> None:
|
|||||||
Test that main() can start backtesting and also ensure we can pass some specific arguments
|
Test that main() can start backtesting and also ensure we can pass some specific arguments
|
||||||
further argument parsing is done in test_arguments.py
|
further argument parsing is done in test_arguments.py
|
||||||
"""
|
"""
|
||||||
backtesting_mock = mocker.patch('freqtrade.optimize.backtesting.start', MagicMock())
|
backtesting_mock = mocker.patch('freqtrade.optimize.start_backtesting', MagicMock())
|
||||||
main(['backtesting'])
|
main(['backtesting'])
|
||||||
assert backtesting_mock.call_count == 1
|
assert backtesting_mock.call_count == 1
|
||||||
call_args = backtesting_mock.call_args[0][0]
|
call_args = backtesting_mock.call_args[0][0]
|
||||||
@ -32,7 +32,7 @@ def test_parse_args_backtesting(mocker) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_main_start_hyperopt(mocker) -> None:
|
def test_main_start_hyperopt(mocker) -> None:
|
||||||
hyperopt_mock = mocker.patch('freqtrade.optimize.hyperopt.start', MagicMock())
|
hyperopt_mock = mocker.patch('freqtrade.optimize.start_hyperopt', MagicMock())
|
||||||
main(['hyperopt'])
|
main(['hyperopt'])
|
||||||
assert hyperopt_mock.call_count == 1
|
assert hyperopt_mock.call_count == 1
|
||||||
call_args = hyperopt_mock.call_args[0][0]
|
call_args = hyperopt_mock.call_args[0][0]
|
||||||
|
@ -41,9 +41,10 @@ from freqtrade.arguments import Arguments, TimeRange
|
|||||||
from freqtrade.data import history
|
from freqtrade.data import history
|
||||||
from freqtrade.data.btanalysis import BT_DATA_COLUMNS, load_backtest_data
|
from freqtrade.data.btanalysis import BT_DATA_COLUMNS, load_backtest_data
|
||||||
from freqtrade.exchange import Exchange
|
from freqtrade.exchange import Exchange
|
||||||
from freqtrade.optimize.backtesting import setup_configuration
|
from freqtrade.optimize import setup_configuration
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.resolvers import StrategyResolver
|
from freqtrade.resolvers import StrategyResolver
|
||||||
|
from freqtrade.state import RunMode
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
_CONF: Dict[str, Any] = {}
|
_CONF: Dict[str, Any] = {}
|
||||||
@ -107,7 +108,7 @@ def get_trading_env(args: Namespace):
|
|||||||
global _CONF
|
global _CONF
|
||||||
|
|
||||||
# Load the configuration
|
# Load the configuration
|
||||||
_CONF.update(setup_configuration(args))
|
_CONF.update(setup_configuration(args, RunMode.BACKTEST))
|
||||||
print(_CONF)
|
print(_CONF)
|
||||||
|
|
||||||
pairs = args.pairs.split(',')
|
pairs = args.pairs.split(',')
|
||||||
|
Loading…
Reference in New Issue
Block a user