Complete Backtesting and Hyperopt unit tests

This commit is contained in:
Gerald Lonlas 2018-03-02 21:46:32 +08:00
parent f4ec073099
commit 6ef7b7d93d
10 changed files with 851 additions and 648 deletions

View File

@ -30,7 +30,7 @@ class Analyze(object):
Init Analyze Init Analyze
:param config: Bot configuration (use the one from Configuration()) :param config: Bot configuration (use the one from Configuration())
""" """
self.logger = Logger(name=__name__).get_logger() self.logger = Logger(name=__name__, level=config.get('loglevel')).get_logger()
self.config = config self.config = config
self.strategy = Strategy(self.config) self.strategy = Strategy(self.config)

View File

@ -19,7 +19,8 @@ class Configuration(object):
""" """
def __init__(self, args: List[str]) -> None: def __init__(self, args: List[str]) -> None:
self.args = args self.args = args
self.logger = Logger(name=__name__).get_logger() self.logging = Logger(name=__name__)
self.logger = self.logging.get_logger()
self.config = self._load_config() self.config = self._load_config()
self.show_info() self.show_info()
@ -35,16 +36,24 @@ class Configuration(object):
config.update({'strategy': self.args.strategy}) config.update({'strategy': self.args.strategy})
# Add dynamic_whitelist if found # Add dynamic_whitelist if found
if self.args.dynamic_whitelist: if 'dynamic_whitelist' in self.args and self.args.dynamic_whitelist:
config.update({'dynamic_whitelist': self.args.dynamic_whitelist}) config.update({'dynamic_whitelist': self.args.dynamic_whitelist})
# Add dry_run_db if found and the bot in dry run # Add dry_run_db if found and the bot in dry run
if self.args.dry_run_db and config.get('dry_run', False): if self.args.dry_run_db and config.get('dry_run', False):
config.update({'dry_run_db': True}) config.update({'dry_run_db': True})
# Load Backtesting / Hyperopt # Log level
if 'loglevel' in self.args and self.args.loglevel:
config.update({'loglevel': self.args.loglevel})
self.logging.set_level(self.args.loglevel)
# Load Backtesting
config = self._load_backtesting_config(config) config = self._load_backtesting_config(config)
# Load Hyperopt
config = self._load_hyperopt_config(config)
return config return config
def _load_config_file(self, path: str) -> Dict[str, Any]: def _load_config_file(self, path: str) -> Dict[str, Any]:
@ -64,7 +73,7 @@ class Configuration(object):
def _load_backtesting_config(self, config: Dict[str, Any]) -> Dict[str, Any]: def _load_backtesting_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
""" """
Extract information for sys.argv and load Backtesting and Hyperopt configuration Extract information for sys.argv and load Backtesting configuration
:return: configuration as dictionary :return: configuration as dictionary
""" """
# If -i/--ticker-interval is used we override the configuration parameter # If -i/--ticker-interval is used we override the configuration parameter
@ -107,6 +116,24 @@ class Configuration(object):
return config return config
def _load_hyperopt_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
"""
Extract information for sys.argv and load Hyperopt configuration
:return: configuration as dictionary
"""
# If --realistic-simulation is used we add it to the configuration
if 'epochs' in self.args and self.args.epochs:
config.update({'epochs': self.args.epochs})
self.logger.info('Parameter --epochs detected ...')
self.logger.info('Will run Hyperopt with for %s epochs ...', config.get('epochs'))
# If --mongodb is used we add it to the configuration
if 'mongodb' in self.args and self.args.mongodb:
config.update({'mongodb': self.args.mongodb})
self.logger.info('Parameter --use-mongodb detected ...')
return config
def _validate_config(self, conf: Dict[str, Any]) -> Dict[str, Any]: def _validate_config(self, conf: Dict[str, Any]) -> Dict[str, Any]:
""" """
Validate the configuration follow the Config Schema Validate the configuration follow the Config Schema

View File

@ -19,9 +19,12 @@ class Logger(object):
:return: None :return: None
""" """
self.name = name self.name = name
self.level = level
self.logger = None self.logger = None
if level is None:
level = logging.INFO
self.level = level
self._init_logger() self._init_logger()
def _init_logger(self) -> None: def _init_logger(self) -> None:

View File

@ -5,7 +5,6 @@ This module contains the backtesting logic
""" """
from typing import Dict, Tuple, Any from typing import Dict, Tuple, Any
import logging
import arrow import arrow
from pandas import DataFrame, Series from pandas import DataFrame, Series
from tabulate import tabulate from tabulate import tabulate
@ -20,6 +19,7 @@ from freqtrade.logger import Logger
from freqtrade.misc import file_dump_json from freqtrade.misc import file_dump_json
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from memory_profiler import profile
class Backtesting(object): class Backtesting(object):
""" """
@ -30,7 +30,9 @@ class Backtesting(object):
backtesting.start() backtesting.start()
""" """
def __init__(self, config: Dict[str, Any]) -> None: def __init__(self, config: Dict[str, Any]) -> None:
self.logging = Logger(name=__name__)
# Init the logger
self.logging = Logger(name=__name__, level=config['loglevel'])
self.logger = self.logging.get_logger() self.logger = self.logging.get_logger()
self.config = config self.config = config
@ -219,6 +221,7 @@ class Backtesting(object):
labels = ['currency', 'profit_percent', 'profit_BTC', 'duration'] labels = ['currency', 'profit_percent', 'profit_BTC', 'duration']
return DataFrame.from_records(trades, columns=labels) return DataFrame.from_records(trades, columns=labels)
@profile(precision=10)
def start(self) -> None: def start(self) -> None:
""" """
Run a backtesting end-to-end Run a backtesting end-to-end
@ -246,10 +249,14 @@ class Backtesting(object):
) )
max_open_trades = self.config.get('max_open_trades', 0) max_open_trades = self.config.get('max_open_trades', 0)
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 = self.get_timeframe(preprocessed)
import pprint
pprint.pprint(min_date)
pprint.pprint(max_date)
self.logger.info( self.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(),

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@ import math
from typing import List from typing import List
from copy import deepcopy from copy import deepcopy
from unittest.mock import MagicMock from unittest.mock import MagicMock
from arrow import Arrow
import pandas as pd import pandas as pd
from freqtrade import optimize from freqtrade import optimize
from freqtrade.optimize.backtesting import Backtesting, start, setup_configuration from freqtrade.optimize.backtesting import Backtesting, start, setup_configuration
@ -255,6 +256,25 @@ def test_backtesting_init(default_conf) -> None:
assert callable(backtesting.populate_sell_trend) assert callable(backtesting.populate_sell_trend)
def test_tickerdata_to_dataframe(default_conf) -> None:
"""
Test Backtesting.tickerdata_to_dataframe() method
"""
timerange = ((None, 'line'), None, -100)
tick = optimize.load_tickerdata_file(None, 'BTC_UNITEST', 1, timerange=timerange)
tickerlist = {'BTC_UNITEST': tick}
backtesting = _BACKTESTING
data = backtesting.tickerdata_to_dataframe(tickerlist)
assert len(data['BTC_UNITEST']) == 100
# Load Analyze to compare the result between Backtesting function and Analyze are the same
analyze = Analyze(default_conf)
data2 = analyze.tickerdata_to_dataframe(tickerlist)
assert data['BTC_UNITEST'].equals(data2['BTC_UNITEST'])
def test_get_timeframe() -> None: def test_get_timeframe() -> None:
""" """
Test Backtesting.get_timeframe() method Test Backtesting.get_timeframe() method
@ -308,8 +328,18 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None:
""" """
Test Backtesting.start() method Test Backtesting.start() method
""" """
mocker.patch.multiple('freqtrade.optimize', load_data=mocked_load_data) def get_timeframe(input1, input2):
mocker.patch('freqtrade.exchange.get_ticker_history', MagicMock) return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
mocker.patch('freqtrade.freqtradebot.Analyze', MagicMock())
mocker.patch('freqtrade.optimize.load_data', mocked_load_data)
mocker.patch('freqtrade.exchange.get_ticker_history')
mocker.patch.multiple(
'freqtrade.optimize.backtesting.Backtesting',
backtest=MagicMock(),
_generate_text_table=MagicMock(return_value='1'),
get_timeframe=get_timeframe,
)
conf = deepcopy(default_conf) conf = deepcopy(default_conf)
conf['exchange']['pair_whitelist'] = ['BTC_UNITEST'] conf['exchange']['pair_whitelist'] = ['BTC_UNITEST']

View File

@ -1,117 +1,108 @@
# pragma pylint: disable=missing-docstring,W0212,C0103 # pragma pylint: disable=missing-docstring,W0212,C0103
import logging import logging
import os
import pytest
from copy import deepcopy
from freqtrade.optimize.hyperopt import calculate_loss, TARGET_TRADES, EXPECTED_MAX_PROFIT, start, \ #from freqtrade.optimize.hyperopt import EXPECTED_MAX_PROFIT, start, \
log_results, save_trials, read_trials, generate_roi_table # log_results, save_trials, read_trials, generate_roi_table
from unittest.mock import MagicMock
from freqtrade.optimize.hyperopt import Hyperopt, start
import freqtrade.tests.conftest as tt # test tools
def test_loss_calculation_prefer_correct_trade_count(): # Avoid to reinit the same object again and again
correct = calculate_loss(1, TARGET_TRADES, 20) _HYPEROPT = Hyperopt(tt.default_conf())
over = calculate_loss(1, TARGET_TRADES + 100, 20)
under = calculate_loss(1, TARGET_TRADES - 100, 20)
assert over > correct
assert under > correct
def test_loss_calculation_prefer_shorter_trades(): # Functions for recurrent object patching
shorter = calculate_loss(1, 100, 20) def create_trials(mocker) -> None:
longer = calculate_loss(1, 100, 30)
assert shorter < longer
def test_loss_calculation_has_limited_profit():
correct = calculate_loss(EXPECTED_MAX_PROFIT, TARGET_TRADES, 20)
over = calculate_loss(EXPECTED_MAX_PROFIT * 2, TARGET_TRADES, 20)
under = calculate_loss(EXPECTED_MAX_PROFIT / 2, TARGET_TRADES, 20)
assert over == correct
assert under > correct
def create_trials(mocker):
""" """
When creating trials, mock the hyperopt Trials so that *by default* When creating trials, mock the hyperopt Trials so that *by default*
- we don't create any pickle'd files in the filesystem - we don't create any pickle'd files in the filesystem
- we might have a pickle'd file so make sure that we return - we might have a pickle'd file so make sure that we return
false when looking for it false when looking for it
""" """
mocker.patch('freqtrade.optimize.hyperopt.TRIALS_FILE', _HYPEROPT.trials_file = os.path.join('freqtrade', 'tests', 'optimize','ut_trials.pickle')
return_value='freqtrade/tests/optimize/ut_trials.pickle')
mocker.patch('freqtrade.optimize.hyperopt.os.path.exists', mocker.patch('freqtrade.optimize.hyperopt.os.path.exists', return_value=False)
return_value=False) mocker.patch('freqtrade.optimize.hyperopt.os.remove', return_value=True)
mocker.patch('freqtrade.optimize.hyperopt.save_trials', mocker.patch('freqtrade.optimize.hyperopt.pickle.dump', return_value=None)
return_value=None)
mocker.patch('freqtrade.optimize.hyperopt.read_trials',
return_value=None)
mocker.patch('freqtrade.optimize.hyperopt.os.remove',
return_value=True)
return mocker.Mock( return mocker.Mock(
results=[{ results=[
'loss': 1, {
'result': 'foo', 'loss': 1,
'status': 'ok' 'result': 'foo',
}], 'status': 'ok'
}
],
best_trial={'misc': {'vals': {'adx': 999}}} best_trial={'misc': {'vals': {'adx': 999}}}
) )
def test_start_calls_fmin(mocker): # Unit tests
trials = create_trials(mocker) def test_loss_calculation_prefer_correct_trade_count() -> None:
mocker.patch('freqtrade.optimize.tickerdata_to_dataframe') """
mocker.patch('freqtrade.optimize.hyperopt.TRIALS', return_value=trials) Test Hyperopt.calculate_loss()
mocker.patch('freqtrade.optimize.hyperopt.sorted', """
return_value=trials.results) hyperopt = _HYPEROPT
mocker.patch('freqtrade.optimize.preprocess')
mocker.patch('freqtrade.optimize.load_data')
mock_fmin = mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={})
args = mocker.Mock(epochs=1, config='config.json.example', mongodb=False, correct = hyperopt.calculate_loss(1, hyperopt.target_trades, 20)
timerange=None) over = hyperopt.calculate_loss(1, hyperopt.target_trades + 100, 20)
start(args) under = hyperopt.calculate_loss(1, hyperopt.target_trades - 100, 20)
assert over > correct
mock_fmin.assert_called_once() assert under > correct
def test_start_uses_mongotrials(mocker): def test_loss_calculation_prefer_shorter_trades() -> None:
mock_mongotrials = mocker.patch('freqtrade.optimize.hyperopt.MongoTrials', """
return_value=create_trials(mocker)) Test Hyperopt.calculate_loss()
mocker.patch('freqtrade.optimize.tickerdata_to_dataframe') """
mocker.patch('freqtrade.optimize.load_data') hyperopt = _HYPEROPT
mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={})
args = mocker.Mock(epochs=1, config='config.json.example', mongodb=True, shorter = hyperopt.calculate_loss(1, 100, 20)
timerange=None) longer = hyperopt.calculate_loss(1, 100, 30)
start(args) assert shorter < longer
mock_mongotrials.assert_called_once()
def test_log_results_if_loss_improves(mocker): def test_loss_calculation_has_limited_profit() -> None:
logger = mocker.patch('freqtrade.optimize.hyperopt.logger.info') hyperopt = _HYPEROPT
global CURRENT_BEST_LOSS
CURRENT_BEST_LOSS = 2
log_results({
'loss': 1,
'current_tries': 1,
'total_tries': 2,
'result': 'foo'
})
logger.assert_called_once() correct = hyperopt.calculate_loss(hyperopt.expected_max_profit, hyperopt.target_trades, 20)
over = hyperopt.calculate_loss(hyperopt.expected_max_profit * 2, hyperopt.target_trades, 20)
under = hyperopt.calculate_loss(hyperopt.expected_max_profit / 2, hyperopt.target_trades, 20)
assert over == correct
assert under > correct
def test_no_log_if_loss_does_not_improve(mocker): def test_log_results_if_loss_improves(caplog) -> None:
logger = mocker.patch('freqtrade.optimize.hyperopt.logger.info') hyperopt = _HYPEROPT
global CURRENT_BEST_LOSS hyperopt.current_best_loss = 2
CURRENT_BEST_LOSS = 2 hyperopt.log_results(
log_results({ {
'loss': 3, 'loss': 1,
}) 'current_tries': 1,
'total_tries': 2,
assert not logger.called 'result': 'foo'
}
)
assert tt.log_has(' 1/2: foo. Loss 1.00000', caplog.record_tuples)
def test_fmin_best_results(mocker, caplog): def test_no_log_if_loss_does_not_improve(caplog) -> None:
caplog.set_level(logging.INFO) hyperopt = _HYPEROPT
hyperopt.current_best_loss = 2
hyperopt.log_results(
{
'loss': 3,
}
)
assert caplog.record_tuples == []
def test_fmin_best_results(mocker, default_conf, caplog) -> None:
fmin_result = { fmin_result = {
"macd_below_zero": 0, "macd_below_zero": 0,
"adx": 1, "adx": 1,
@ -136,38 +127,65 @@ def test_fmin_best_results(mocker, caplog):
"roi_p3": 3, "roi_p3": 3,
} }
mocker.patch('freqtrade.optimize.hyperopt.MongoTrials', return_value=create_trials(mocker)) conf = deepcopy(default_conf)
mocker.patch('freqtrade.optimize.tickerdata_to_dataframe') conf.update({'config': 'config.json.example'})
mocker.patch('freqtrade.optimize.load_data') conf.update({'epochs': 1})
mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value=fmin_result) conf.update({'timerange': None})
args = mocker.Mock(epochs=1, config='config.json.example', mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
timerange=None) mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value=fmin_result)
start(args) mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf)
mocker.patch('freqtrade.logger.Logger.set_format', MagicMock())
hyperopt = Hyperopt(conf)
hyperopt.trials = create_trials(mocker)
hyperopt.tickerdata_to_dataframe = MagicMock()
hyperopt.start()
exists = [ exists = [
'Best parameters', 'Best parameters:',
'"adx": {\n "enabled": true,\n "value": 15.0\n },', '"adx": {\n "enabled": true,\n "value": 15.0\n },',
'"fastd": {\n "enabled": true,\n "value": 40.0\n },',
'"green_candle": {\n "enabled": true\n },', '"green_candle": {\n "enabled": true\n },',
'"macd_below_zero": {\n "enabled": false\n },',
'"mfi": {\n "enabled": false\n },', '"mfi": {\n "enabled": false\n },',
'"over_sar": {\n "enabled": false\n },',
'"roi_p1": 1.0,',
'"roi_p2": 2.0,',
'"roi_p3": 3.0,',
'"roi_t1": 1.0,',
'"roi_t2": 2.0,',
'"roi_t3": 3.0,',
'"rsi": {\n "enabled": true,\n "value": 37.0\n },',
'"stoploss": -0.1,',
'"trigger": {\n "type": "faststoch10"\n },', '"trigger": {\n "type": "faststoch10"\n },',
'"stoploss": -0.1', '"uptrend_long_ema": {\n "enabled": true\n },',
'"uptrend_short_ema": {\n "enabled": false\n },',
'"uptrend_sma": {\n "enabled": false\n }',
'ROI table:\n{\'0\': 6.0, \'3.0\': 3.0, \'5.0\': 1.0, \'6.0\': 0}',
'Best Result:\nfoo'
] ]
for line in exists: for line in exists:
assert line in caplog.text assert line in caplog.text
def test_fmin_throw_value_error(mocker, caplog): def test_fmin_throw_value_error(mocker, default_conf, caplog) -> None:
caplog.set_level(logging.INFO) mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
mocker.patch('freqtrade.optimize.hyperopt.MongoTrials', return_value=create_trials(mocker))
mocker.patch('freqtrade.optimize.tickerdata_to_dataframe')
mocker.patch('freqtrade.optimize.load_data')
mocker.patch('freqtrade.optimize.hyperopt.fmin', side_effect=ValueError()) mocker.patch('freqtrade.optimize.hyperopt.fmin', side_effect=ValueError())
args = mocker.Mock(epochs=1, config='config.json.example', conf = deepcopy(default_conf)
timerange=None) conf.update({'config': 'config.json.example'})
start(args) conf.update({'epochs': 1})
conf.update({'timerange': None})
mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf)
mocker.patch('freqtrade.logger.Logger.set_format', MagicMock())
hyperopt = Hyperopt(conf)
hyperopt.trials = create_trials(mocker)
hyperopt.tickerdata_to_dataframe = MagicMock()
hyperopt.start()
exists = [ exists = [
'Best Result:', 'Best Result:',
@ -179,68 +197,80 @@ def test_fmin_throw_value_error(mocker, caplog):
assert line in caplog.text assert line in caplog.text
def test_resuming_previous_hyperopt_results_succeeds(mocker): def test_resuming_previous_hyperopt_results_succeeds(mocker, default_conf) -> None:
import freqtrade.optimize.hyperopt as hyperopt
trials = create_trials(mocker) trials = create_trials(mocker)
mocker.patch('freqtrade.optimize.hyperopt.TRIALS',
return_value=trials)
mocker.patch('freqtrade.optimize.hyperopt.os.path.exists',
return_value=True)
mocker.patch('freqtrade.optimize.hyperopt.len',
return_value=len(trials.results))
mock_read = mocker.patch('freqtrade.optimize.hyperopt.read_trials',
return_value=trials)
mock_save = mocker.patch('freqtrade.optimize.hyperopt.save_trials',
return_value=None)
mocker.patch('freqtrade.optimize.hyperopt.sorted',
return_value=trials.results)
mocker.patch('freqtrade.optimize.preprocess')
mocker.patch('freqtrade.optimize.load_data')
mocker.patch('freqtrade.optimize.hyperopt.fmin',
return_value={})
args = mocker.Mock(epochs=1,
config='config.json.example',
mongodb=False,
timerange=None)
start(args) conf = deepcopy(default_conf)
conf.update({'config': 'config.json.example'})
conf.update({'epochs': 1})
conf.update({'mongodb': False})
conf.update({'timerange': None})
mocker.patch('freqtrade.optimize.hyperopt.os.path.exists', return_value=True)
mocker.patch('freqtrade.optimize.hyperopt.len', return_value=len(trials.results))
mock_read = mocker.patch(
'freqtrade.optimize.hyperopt.Hyperopt.read_trials',
return_value=trials
)
mock_save = mocker.patch(
'freqtrade.optimize.hyperopt.Hyperopt.save_trials',
return_value=None
)
mocker.patch('freqtrade.optimize.hyperopt.sorted', return_value=trials.results)
mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={})
mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf)
mocker.patch('freqtrade.logger.Logger.set_format', MagicMock())
hyperopt = Hyperopt(conf)
hyperopt.trials = trials
hyperopt.tickerdata_to_dataframe = MagicMock()
hyperopt.start()
mock_read.assert_called_once() mock_read.assert_called_once()
mock_save.assert_called_once() mock_save.assert_called_once()
current_tries = hyperopt._CURRENT_TRIES current_tries = hyperopt.current_tries
total_tries = hyperopt.TOTAL_TRIES total_tries = hyperopt.total_tries
assert current_tries == len(trials.results) assert current_tries == len(trials.results)
assert total_tries == (current_tries + len(trials.results)) assert total_tries == (current_tries + len(trials.results))
def test_save_trials_saves_trials(mocker): def test_save_trials_saves_trials(mocker, caplog) -> None:
create_trials(mocker)
mock_dump = mocker.patch('freqtrade.optimize.hyperopt.pickle.dump', return_value=None)
hyperopt = _HYPEROPT
mocker.patch('freqtrade.optimize.hyperopt.open', return_value=hyperopt.trials_file)
hyperopt.save_trials()
assert tt.log_has(
'Saving Trials to \'freqtrade/tests/optimize/ut_trials.pickle\'',
caplog.record_tuples
)
mock_dump.assert_called_once()
def test_read_trials_returns_trials_file(mocker, default_conf, caplog) -> None:
trials = create_trials(mocker) trials = create_trials(mocker)
mock_dump = mocker.patch('freqtrade.optimize.hyperopt.pickle.dump', mock_load = mocker.patch('freqtrade.optimize.hyperopt.pickle.load', return_value=trials)
return_value=None) mock_open = mocker.patch('freqtrade.optimize.hyperopt.open', return_value=mock_load)
trials_path = mocker.patch('freqtrade.optimize.hyperopt.TRIALS_FILE',
return_value='ut_trials.pickle')
mocker.patch('freqtrade.optimize.hyperopt.open',
return_value=trials_path)
save_trials(trials, trials_path)
mock_dump.assert_called_once_with(trials, trials_path) hyperopt = _HYPEROPT
hyperopt_trial = hyperopt.read_trials()
assert tt.log_has(
def test_read_trials_returns_trials_file(mocker): 'Reading Trials from \'freqtrade/tests/optimize/ut_trials.pickle\'',
trials = create_trials(mocker) caplog.record_tuples
mock_load = mocker.patch('freqtrade.optimize.hyperopt.pickle.load', )
return_value=trials) assert hyperopt_trial == trials
mock_open = mocker.patch('freqtrade.optimize.hyperopt.open',
return_value=mock_load)
assert read_trials() == trials
mock_open.assert_called_once() mock_open.assert_called_once()
mock_load.assert_called_once() mock_load.assert_called_once()
def test_roi_table_generation(): def test_roi_table_generation() -> None:
params = { params = {
'roi_t1': 5, 'roi_t1': 5,
'roi_t2': 10, 'roi_t2': 10,
@ -249,4 +279,49 @@ def test_roi_table_generation():
'roi_p2': 2, 'roi_p2': 2,
'roi_p3': 3, 'roi_p3': 3,
} }
assert generate_roi_table(params) == {'0': 6, '15': 3, '25': 1, '30': 0}
hyperopt = _HYPEROPT
assert hyperopt.generate_roi_table(params) == {'0': 6, '15': 3, '25': 1, '30': 0}
def test_start_calls_fmin(mocker, default_conf) -> None:
trials = create_trials(mocker)
mocker.patch('freqtrade.optimize.hyperopt.sorted', return_value=trials.results)
mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
mock_fmin = mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={})
conf = deepcopy(default_conf)
conf.update({'config': 'config.json.example'})
conf.update({'epochs': 1})
conf.update({'mongodb': False})
conf.update({'timerange': None})
hyperopt = Hyperopt(conf)
hyperopt.trials = trials
hyperopt.tickerdata_to_dataframe = MagicMock()
hyperopt.start()
mock_fmin.assert_called_once()
def test_start_uses_mongotrials(mocker, default_conf) -> None:
mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
mock_fmin = mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={})
mock_mongotrials = mocker.patch(
'freqtrade.optimize.hyperopt.MongoTrials',
return_value=create_trials(mocker)
)
conf = deepcopy(default_conf)
conf.update({'config': 'config.json.example'})
conf.update({'epochs': 1})
conf.update({'mongodb': True})
conf.update({'timerange': None})
mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf)
hyperopt = Hyperopt(conf)
hyperopt.tickerdata_to_dataframe = MagicMock()
hyperopt.start()
mock_mongotrials.assert_called_once()
mock_fmin.assert_called_once()

View File

@ -6,7 +6,6 @@ import logging
import uuid import uuid
from shutil import copyfile from shutil import copyfile
from freqtrade import optimize from freqtrade import optimize
from freqtrade.analyze import Analyze
from freqtrade.optimize.__init__ import make_testdata_path, download_pairs,\ from freqtrade.optimize.__init__ import make_testdata_path, download_pairs,\
download_backtesting_testdata, load_tickerdata_file, trim_tickerlist download_backtesting_testdata, load_tickerdata_file, trim_tickerlist
from freqtrade.misc import file_dump_json from freqtrade.misc import file_dump_json
@ -220,16 +219,6 @@ def test_init(default_conf, mocker) -> None:
) )
def test_tickerdata_to_dataframe(default_conf) -> None:
analyze = Analyze(default_conf)
timerange = ((None, 'line'), None, -100)
tick = load_tickerdata_file(None, 'BTC_UNITEST', 1, timerange=timerange)
tickerlist = {'BTC_UNITEST': tick}
data = analyze.tickerdata_to_dataframe(tickerlist)
assert len(data['BTC_UNITEST']) == 100
def test_trim_tickerlist() -> None: def test_trim_tickerlist() -> None:
with open('freqtrade/tests/testdata/BTC_ETH-1.json') as data_file: with open('freqtrade/tests/testdata/BTC_ETH-1.json') as data_file:
ticker_list = json.load(data_file) ticker_list = json.load(data_file)

View File

@ -10,8 +10,9 @@ import logging
import arrow import arrow
from pandas import DataFrame from pandas import DataFrame
import freqtrade.tests.conftest as tt # test tools
from freqtrade.analyze import Analyze, SignalType from freqtrade.analyze import Analyze, SignalType
from freqtrade.optimize.__init__ import load_tickerdata_file
import freqtrade.tests.conftest as tt # test tools
# Avoid to reinit the same object again and again # Avoid to reinit the same object again and again
@ -173,3 +174,16 @@ def test_parse_ticker_dataframe(ticker_history, ticker_history_without_bv):
# Test file without BV data # Test file without BV data
dataframe = Analyze.parse_ticker_dataframe(ticker_history_without_bv) dataframe = Analyze.parse_ticker_dataframe(ticker_history_without_bv)
assert dataframe.columns.tolist() == columns assert dataframe.columns.tolist() == columns
def test_tickerdata_to_dataframe(default_conf) -> None:
"""
Test Analyze.tickerdata_to_dataframe() method
"""
analyze = Analyze(default_conf)
timerange = ((None, 'line'), None, -100)
tick = load_tickerdata_file(None, 'BTC_UNITEST', 1, timerange=timerange)
tickerlist = {'BTC_UNITEST': tick}
data = analyze.tickerdata_to_dataframe(tickerlist)
assert len(data['BTC_UNITEST']) == 100

View File

@ -1,17 +1,19 @@
# pragma pylint: disable=missing-docstring, C0103 # pragma pylint: disable=missing-docstring, C0103
import pandas import pandas
import freqtrade.optimize from freqtrade.optimize import load_data
from freqtrade import analyze from freqtrade.analyze import Analyze, SignalType
_pairs = ['BTC_ETH'] _pairs = ['BTC_ETH']
def load_dataframe_pair(pairs): def load_dataframe_pair(pairs):
ld = freqtrade.optimize.load_data(None, ticker_interval=5, pairs=pairs) ld = load_data(None, ticker_interval=5, pairs=pairs)
assert isinstance(ld, dict) assert isinstance(ld, dict)
assert isinstance(pairs[0], str) assert isinstance(pairs[0], str)
dataframe = ld[pairs[0]] dataframe = ld[pairs[0]]
analyze = Analyze({'strategy': 'default_strategy'})
dataframe = analyze.analyze_ticker(dataframe) dataframe = analyze.analyze_ticker(dataframe)
return dataframe return dataframe