Merge branch 'develop' into pr/hroff-1902/1804
This commit is contained in:
commit
b9d7bb2d8e
@ -22,7 +22,7 @@ requirements:
|
|||||||
- requirements.txt
|
- requirements.txt
|
||||||
- requirements-dev.txt
|
- requirements-dev.txt
|
||||||
- requirements-plot.txt
|
- requirements-plot.txt
|
||||||
- requirements-pi.txt
|
- requirements-common.txt
|
||||||
|
|
||||||
|
|
||||||
# configure the branch prefix the bot is using
|
# configure the branch prefix the bot is using
|
||||||
|
@ -16,7 +16,7 @@ RUN cd /tmp && /tmp/install_ta-lib.sh && rm -r /tmp/*ta-lib*
|
|||||||
ENV LD_LIBRARY_PATH /usr/local/lib
|
ENV LD_LIBRARY_PATH /usr/local/lib
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
COPY requirements.txt /freqtrade/
|
COPY requirements.txt requirements-common.txt /freqtrade/
|
||||||
RUN pip install numpy --no-cache-dir \
|
RUN pip install numpy --no-cache-dir \
|
||||||
&& pip install -r requirements.txt --no-cache-dir
|
&& pip install -r requirements.txt --no-cache-dir
|
||||||
|
|
||||||
|
@ -27,9 +27,9 @@ RUN wget https://github.com/jjhelmus/berryconda/releases/download/v2.0.0/Berryco
|
|||||||
&& rm Berryconda3-2.0.0-Linux-armv7l.sh
|
&& rm Berryconda3-2.0.0-Linux-armv7l.sh
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
COPY requirements-pi.txt /freqtrade/
|
COPY requirements-common.txt /freqtrade/
|
||||||
RUN ~/berryconda3/bin/conda install -y numpy pandas scipy \
|
RUN ~/berryconda3/bin/conda install -y numpy pandas scipy \
|
||||||
&& ~/berryconda3/bin/pip install -r requirements-pi.txt --no-cache-dir
|
&& ~/berryconda3/bin/pip install -r requirements-common.txt --no-cache-dir
|
||||||
|
|
||||||
# Install and execute
|
# Install and execute
|
||||||
COPY . /freqtrade/
|
COPY . /freqtrade/
|
||||||
|
@ -326,7 +326,7 @@ conda activate freqtrade
|
|||||||
conda install scipy pandas numpy
|
conda install scipy pandas numpy
|
||||||
|
|
||||||
sudo apt install libffi-dev
|
sudo apt install libffi-dev
|
||||||
python3 -m pip install -r requirements-pi.txt
|
python3 -m pip install -r requirements-common.txt
|
||||||
python3 -m pip install -e .
|
python3 -m pip install -e .
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Callable, Dict, List, Optional
|
||||||
|
|
||||||
from jsonschema import Draft4Validator, validators
|
from jsonschema import Draft4Validator, validators
|
||||||
from jsonschema.exceptions import ValidationError, best_match
|
from jsonschema.exceptions import ValidationError, best_match
|
||||||
@ -17,7 +17,6 @@ from freqtrade.exchange import is_exchange_supported, supported_exchanges
|
|||||||
from freqtrade.misc import deep_merge_dicts
|
from freqtrade.misc import deep_merge_dicts
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -95,14 +94,8 @@ class Configuration(object):
|
|||||||
# Load Common configuration
|
# Load Common configuration
|
||||||
config = self._load_common_config(config)
|
config = self._load_common_config(config)
|
||||||
|
|
||||||
# Load Backtesting
|
# Load Optimize configurations
|
||||||
config = self._load_backtesting_config(config)
|
config = self._load_optimize_config(config)
|
||||||
|
|
||||||
# Load Edge
|
|
||||||
config = self._load_edge_config(config)
|
|
||||||
|
|
||||||
# Load Hyperopt
|
|
||||||
config = self._load_hyperopt_config(config)
|
|
||||||
|
|
||||||
# Set runmode
|
# Set runmode
|
||||||
if not self.runmode:
|
if not self.runmode:
|
||||||
@ -216,25 +209,41 @@ class Configuration(object):
|
|||||||
logger.info(f'Created data directory: {datadir}')
|
logger.info(f'Created data directory: {datadir}')
|
||||||
return datadir
|
return datadir
|
||||||
|
|
||||||
def _load_backtesting_config(self, config: Dict[str, Any]) -> Dict[str, Any]: # noqa: C901
|
def _args_to_config(self, config: Dict[str, Any], argname: str,
|
||||||
|
logstring: str, logfun: Optional[Callable] = None) -> None:
|
||||||
"""
|
"""
|
||||||
Extract information for sys.argv and load Backtesting configuration
|
:param config: Configuration dictionary
|
||||||
|
:param argname: Argumentname in self.args - will be copied to config dict.
|
||||||
|
:param logstring: Logging String
|
||||||
|
:param logfun: logfun is applied to the configuration entry before passing
|
||||||
|
that entry to the log string using .format().
|
||||||
|
sample: logfun=len (prints the length of the found
|
||||||
|
configuration instead of the content)
|
||||||
|
"""
|
||||||
|
if argname in self.args and getattr(self.args, argname):
|
||||||
|
|
||||||
|
config.update({argname: getattr(self.args, argname)})
|
||||||
|
if logfun:
|
||||||
|
logger.info(logstring.format(logfun(config[argname])))
|
||||||
|
else:
|
||||||
|
logger.info(logstring.format(config[argname]))
|
||||||
|
|
||||||
|
def _load_optimize_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Extract information for sys.argv and load Optimize configuration
|
||||||
:return: configuration as dictionary
|
:return: configuration as dictionary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This will override the strategy configuration
|
# This will override the strategy configuration
|
||||||
if 'ticker_interval' in self.args and self.args.ticker_interval:
|
self._args_to_config(config, argname='ticker_interval',
|
||||||
config.update({'ticker_interval': self.args.ticker_interval})
|
logstring='Parameter -i/--ticker-interval detected ... '
|
||||||
logger.info('Parameter -i/--ticker-interval detected ...')
|
'Using ticker_interval: {} ...')
|
||||||
logger.info('Using ticker_interval: %s ...', config.get('ticker_interval'))
|
|
||||||
|
|
||||||
if 'live' in self.args and self.args.live:
|
self._args_to_config(config, argname='live',
|
||||||
config.update({'live': True})
|
logstring='Parameter -l/--live detected ...')
|
||||||
logger.info('Parameter -l/--live detected ...')
|
|
||||||
|
|
||||||
if 'position_stacking' in self.args and self.args.position_stacking:
|
self._args_to_config(config, argname='position_stacking',
|
||||||
config.update({'position_stacking': True})
|
logstring='Parameter --enable-position-stacking detected ...')
|
||||||
logger.info('Parameter --enable-position-stacking detected ...')
|
|
||||||
|
|
||||||
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})
|
||||||
@ -247,14 +256,12 @@ 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' in self.args and self.args.stake_amount:
|
self._args_to_config(config, argname='stake_amount',
|
||||||
config.update({'stake_amount': self.args.stake_amount})
|
logstring='Parameter --stake_amount detected, '
|
||||||
logger.info('Parameter --stake_amount detected, overriding stake_amount to: %s ...',
|
'overriding stake_amount to: {} ...')
|
||||||
config.get('stake_amount'))
|
|
||||||
|
|
||||||
if 'timerange' in self.args and self.args.timerange:
|
self._args_to_config(config, argname='timerange',
|
||||||
config.update({'timerange': self.args.timerange})
|
logstring='Parameter --timerange detected: {} ...')
|
||||||
logger.info('Parameter --timerange detected: %s ...', self.args.timerange)
|
|
||||||
|
|
||||||
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)})
|
||||||
@ -262,38 +269,22 @@ class Configuration(object):
|
|||||||
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 'refresh_pairs' in self.args and self.args.refresh_pairs:
|
self._args_to_config(config, argname='refresh_pairs',
|
||||||
config.update({'refresh_pairs': True})
|
logstring='Parameter -r/--refresh-pairs-cached detected ...')
|
||||||
logger.info('Parameter -r/--refresh-pairs-cached detected ...')
|
|
||||||
|
|
||||||
if 'strategy_list' in self.args and self.args.strategy_list:
|
self._args_to_config(config, argname='strategy_list',
|
||||||
config.update({'strategy_list': self.args.strategy_list})
|
logstring='Using strategy list of {} Strategies', logfun=len)
|
||||||
logger.info('Using strategy list of %s Strategies', len(self.args.strategy_list))
|
|
||||||
|
|
||||||
if 'ticker_interval' in self.args and self.args.ticker_interval:
|
self._args_to_config(config, argname='ticker_interval',
|
||||||
config.update({'ticker_interval': self.args.ticker_interval})
|
logstring='Overriding ticker interval with Command line argument')
|
||||||
logger.info('Overriding ticker interval with Command line argument')
|
|
||||||
|
|
||||||
if 'export' in self.args and self.args.export:
|
self._args_to_config(config, argname='export',
|
||||||
config.update({'export': self.args.export})
|
logstring='Parameter --export detected: {} ...')
|
||||||
logger.info('Parameter --export detected: %s ...', self.args.export)
|
|
||||||
|
|
||||||
if 'export' in config and 'exportfilename' in self.args and self.args.exportfilename:
|
self._args_to_config(config, argname='exportfilename',
|
||||||
config.update({'exportfilename': self.args.exportfilename})
|
logstring='Storing backtest results to {} ...')
|
||||||
logger.info('Storing backtest results to %s ...', self.args.exportfilename)
|
|
||||||
|
|
||||||
return config
|
|
||||||
|
|
||||||
def _load_edge_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
Extract information for sys.argv and load Edge configuration
|
|
||||||
:return: configuration as dictionary
|
|
||||||
"""
|
|
||||||
|
|
||||||
if 'timerange' in self.args and self.args.timerange:
|
|
||||||
config.update({'timerange': self.args.timerange})
|
|
||||||
logger.info('Parameter --timerange detected: %s ...', self.args.timerange)
|
|
||||||
|
|
||||||
|
# Edge section:
|
||||||
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]})
|
||||||
@ -301,48 +292,26 @@ 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 'refresh_pairs' in self.args and self.args.refresh_pairs:
|
# Hyperopt section
|
||||||
config.update({'refresh_pairs': True})
|
self._args_to_config(config, argname='hyperopt',
|
||||||
logger.info('Parameter -r/--refresh-pairs-cached detected ...')
|
logstring='Using Hyperopt file {}')
|
||||||
|
|
||||||
return config
|
self._args_to_config(config, argname='epochs',
|
||||||
|
logstring='Parameter --epochs detected ... '
|
||||||
|
'Will run Hyperopt with for {} epochs ...'
|
||||||
|
)
|
||||||
|
|
||||||
def _load_hyperopt_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
|
self._args_to_config(config, argname='spaces',
|
||||||
"""
|
logstring='Parameter -s/--spaces detected: {}')
|
||||||
Extract information for sys.argv and load Hyperopt configuration
|
|
||||||
:return: configuration as dictionary
|
|
||||||
"""
|
|
||||||
|
|
||||||
if "hyperopt" in self.args:
|
self._args_to_config(config, argname='print_all',
|
||||||
# Add the hyperopt file to use
|
logstring='Parameter --print-all detected ...')
|
||||||
config.update({'hyperopt': self.args.hyperopt})
|
|
||||||
|
|
||||||
if 'epochs' in self.args and self.args.epochs:
|
self._args_to_config(config, argname='hyperopt_jobs',
|
||||||
config.update({'epochs': self.args.epochs})
|
logstring='Parameter -j/--job-workers detected: {}')
|
||||||
logger.info('Parameter --epochs detected ...')
|
|
||||||
logger.info('Will run Hyperopt with for %s epochs ...', config.get('epochs'))
|
|
||||||
|
|
||||||
if 'spaces' in self.args and self.args.spaces:
|
|
||||||
config.update({'spaces': self.args.spaces})
|
|
||||||
logger.info('Parameter -s/--spaces detected: %s', config.get('spaces'))
|
|
||||||
|
|
||||||
if 'print_all' in self.args and self.args.print_all:
|
|
||||||
config.update({'print_all': self.args.print_all})
|
|
||||||
logger.info('Parameter --print-all detected: %s', config.get('print_all'))
|
|
||||||
|
|
||||||
if 'hyperopt_jobs' in self.args and self.args.hyperopt_jobs:
|
|
||||||
config.update({'hyperopt_jobs': self.args.hyperopt_jobs})
|
|
||||||
logger.info('Parameter -j/--job-workers detected: %s', config.get('hyperopt_jobs'))
|
|
||||||
|
|
||||||
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:
|
|
||||||
config.update({'hyperopt_random_state': self.args.hyperopt_random_state})
|
|
||||||
logger.info("Parameter --random-state detected: %s",
|
|
||||||
config.get('hyperopt_random_state'))
|
|
||||||
|
|
||||||
|
self._args_to_config(config, argname='hyperopt_random_state',
|
||||||
|
logstring='Parameter --random-state detected: {}')
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def _validate_config_schema(self, conf: Dict[str, Any]) -> Dict[str, Any]:
|
def _validate_config_schema(self, conf: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
@ -23,7 +23,7 @@ from freqtrade.optimize.backtesting import (Backtesting, setup_configuration,
|
|||||||
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
|
||||||
from freqtrade.tests.conftest import log_has, patch_exchange
|
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
|
||||||
|
|
||||||
|
|
||||||
def get_args(args) -> List[str]:
|
def get_args(args) -> List[str]:
|
||||||
@ -190,7 +190,7 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
|||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert not log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert not log_has_re('Parameter -i/--ticker-interval detected .*', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'live' not in config
|
assert 'live' not in config
|
||||||
assert not log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
assert not log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
||||||
@ -242,11 +242,8 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) ->
|
|||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
||||||
assert log_has(
|
caplog.record_tuples)
|
||||||
'Using ticker_interval: 1m ...',
|
|
||||||
caplog.record_tuples
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'live' in config
|
assert 'live' in config
|
||||||
assert log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
assert log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
||||||
@ -853,8 +850,7 @@ def test_backtest_start_live(default_conf, mocker, caplog):
|
|||||||
start(args)
|
start(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 ...',
|
'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
||||||
'Using ticker_interval: 1m ...',
|
|
||||||
'Parameter -l/--live detected ...',
|
'Parameter -l/--live detected ...',
|
||||||
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
||||||
'Parameter --timerange detected: -100 ...',
|
'Parameter --timerange detected: -100 ...',
|
||||||
@ -912,8 +908,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog):
|
|||||||
|
|
||||||
# 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 ...',
|
'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
||||||
'Using ticker_interval: 1m ...',
|
|
||||||
'Parameter -l/--live detected ...',
|
'Parameter -l/--live detected ...',
|
||||||
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
||||||
'Parameter --timerange detected: -100 ...',
|
'Parameter --timerange detected: -100 ...',
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
# pragma pylint: disable=missing-docstring, C0103, C0330
|
# pragma pylint: disable=missing-docstring, C0103, C0330
|
||||||
# pragma pylint: disable=protected-access, too-many-lines, invalid-name, too-many-arguments
|
# pragma pylint: disable=protected-access, too-many-lines, invalid-name, too-many-arguments
|
||||||
|
|
||||||
from unittest.mock import MagicMock
|
|
||||||
import json
|
import json
|
||||||
from typing import List
|
from typing import List
|
||||||
from freqtrade.edge import PairInfo
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.optimize.edge_cli import (EdgeCli, setup_configuration, start)
|
from freqtrade.edge import PairInfo
|
||||||
|
from freqtrade.optimize.edge_cli import EdgeCli, setup_configuration, start
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
from freqtrade.tests.conftest import log_has, patch_exchange
|
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
|
||||||
|
|
||||||
|
|
||||||
def get_args(args) -> List[str]:
|
def get_args(args) -> List[str]:
|
||||||
@ -40,7 +41,7 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
|||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert not log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert not log_has_re('Parameter -i/--ticker-interval detected .*', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'refresh_pairs' not in config
|
assert 'refresh_pairs' not in config
|
||||||
assert not log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
assert not log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
||||||
@ -79,11 +80,8 @@ def test_setup_edge_configuration_with_arguments(mocker, edge_conf, caplog) -> N
|
|||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
||||||
assert log_has(
|
caplog.record_tuples)
|
||||||
'Using ticker_interval: 1m ...',
|
|
||||||
caplog.record_tuples
|
|
||||||
)
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# pragma pylint: disable=missing-docstring,W0212,C0103
|
# pragma pylint: disable=missing-docstring,W0212,C0103
|
||||||
from datetime import datetime
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
from datetime import datetime
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@ -10,11 +10,11 @@ import pytest
|
|||||||
from freqtrade import DependencyException
|
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, setup_configuration
|
|
||||||
from freqtrade.optimize.default_hyperopt import DefaultHyperOpts
|
from freqtrade.optimize.default_hyperopt import DefaultHyperOpts
|
||||||
from freqtrade.resolvers import StrategyResolver, HyperOptResolver
|
from freqtrade.optimize.hyperopt import Hyperopt, setup_configuration, start
|
||||||
|
from freqtrade.resolvers import HyperOptResolver
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
from freqtrade.tests.conftest import log_has, 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
|
||||||
|
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca
|
|||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert not log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert not log_has_re('Parameter -i/--ticker-interval detected .*', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'live' not in config
|
assert 'live' not in config
|
||||||
assert not log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
assert not log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
||||||
@ -114,11 +114,8 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
|
|||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
||||||
assert log_has(
|
caplog.record_tuples)
|
||||||
'Using ticker_interval: 1m ...',
|
|
||||||
caplog.record_tuples
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'position_stacking' in config
|
assert 'position_stacking' in config
|
||||||
assert log_has('Parameter --enable-position-stacking detected ...', caplog.record_tuples)
|
assert log_has('Parameter --enable-position-stacking detected ...', caplog.record_tuples)
|
||||||
@ -137,7 +134,8 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert 'epochs' in config
|
assert 'epochs' in config
|
||||||
assert log_has('Parameter --epochs detected ...', caplog.record_tuples)
|
assert log_has('Parameter --epochs detected ... Will run Hyperopt with for 1000 epochs ...',
|
||||||
|
caplog.record_tuples)
|
||||||
|
|
||||||
assert 'spaces' in config
|
assert 'spaces' in config
|
||||||
assert log_has(
|
assert log_has(
|
||||||
@ -145,7 +143,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
|
|||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'print_all' in config
|
assert 'print_all' in config
|
||||||
assert log_has('Parameter --print-all detected: True', caplog.record_tuples)
|
assert log_has('Parameter --print-all detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
|
def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
|
||||||
@ -185,7 +183,6 @@ def test_start(mocker, default_conf, caplog) -> None:
|
|||||||
'--epochs', '5'
|
'--epochs', '5'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
StrategyResolver({'strategy': 'DefaultStrategy'})
|
|
||||||
start(args)
|
start(args)
|
||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
@ -214,7 +211,6 @@ def test_start_failure(mocker, default_conf, caplog) -> None:
|
|||||||
'--epochs', '5'
|
'--epochs', '5'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
StrategyResolver({'strategy': 'DefaultStrategy'})
|
|
||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
start(args)
|
start(args)
|
||||||
assert log_has(
|
assert log_has(
|
||||||
@ -224,7 +220,6 @@ def test_start_failure(mocker, default_conf, caplog) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_loss_calculation_prefer_correct_trade_count(hyperopt) -> None:
|
def test_loss_calculation_prefer_correct_trade_count(hyperopt) -> None:
|
||||||
StrategyResolver({'strategy': 'DefaultStrategy'})
|
|
||||||
|
|
||||||
correct = hyperopt.calculate_loss(1, hyperopt.target_trades, 20)
|
correct = hyperopt.calculate_loss(1, hyperopt.target_trades, 20)
|
||||||
over = hyperopt.calculate_loss(1, hyperopt.target_trades + 100, 20)
|
over = hyperopt.calculate_loss(1, hyperopt.target_trades + 100, 20)
|
||||||
|
@ -360,11 +360,8 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
|
|||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
||||||
assert log_has(
|
caplog.record_tuples)
|
||||||
'Using ticker_interval: 1m ...',
|
|
||||||
caplog.record_tuples
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'live' in config
|
assert 'live' in config
|
||||||
assert log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
assert log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
||||||
@ -425,11 +422,8 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non
|
|||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
||||||
assert log_has(
|
caplog.record_tuples)
|
||||||
'Using ticker_interval: 1m ...',
|
|
||||||
caplog.record_tuples
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'strategy_list' in config
|
assert 'strategy_list' in config
|
||||||
assert log_has('Using strategy list of 2 Strategies', caplog.record_tuples)
|
assert log_has('Using strategy list of 2 Strategies', caplog.record_tuples)
|
||||||
@ -463,8 +457,8 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None:
|
|||||||
|
|
||||||
assert 'epochs' in config
|
assert 'epochs' in config
|
||||||
assert int(config['epochs']) == 10
|
assert int(config['epochs']) == 10
|
||||||
assert log_has('Parameter --epochs detected ...', caplog.record_tuples)
|
assert log_has('Parameter --epochs detected ... Will run Hyperopt with for 10 epochs ...',
|
||||||
assert log_has('Will run Hyperopt with for 10 epochs ...', caplog.record_tuples)
|
caplog.record_tuples)
|
||||||
|
|
||||||
assert 'spaces' in config
|
assert 'spaces' in config
|
||||||
assert config['spaces'] == ['all']
|
assert config['spaces'] == ['all']
|
||||||
|
@ -7,10 +7,11 @@ import pytest
|
|||||||
|
|
||||||
from freqtrade import OperationalException
|
from freqtrade import OperationalException
|
||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.worker import Worker
|
from freqtrade.freqtradebot import FreqtradeBot
|
||||||
from freqtrade.main import main
|
from freqtrade.main import main
|
||||||
from freqtrade.state import State
|
from freqtrade.state import State
|
||||||
from freqtrade.tests.conftest import log_has, patch_exchange
|
from freqtrade.tests.conftest import log_has, patch_exchange
|
||||||
|
from freqtrade.worker import Worker
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_backtesting(mocker) -> None:
|
def test_parse_args_backtesting(mocker) -> None:
|
||||||
@ -107,24 +108,30 @@ def test_main_operational_exception(mocker, default_conf, caplog) -> None:
|
|||||||
def test_main_reload_conf(mocker, default_conf, caplog) -> None:
|
def test_main_reload_conf(mocker, default_conf, caplog) -> None:
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cleanup', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cleanup', MagicMock())
|
||||||
mocker.patch('freqtrade.worker.Worker._worker', MagicMock(return_value=State.RELOAD_CONF))
|
# Simulate Running, reload, running workflow
|
||||||
|
worker_mock = MagicMock(side_effect=[State.RUNNING,
|
||||||
|
State.RELOAD_CONF,
|
||||||
|
State.RUNNING,
|
||||||
|
OperationalException("Oh snap!")])
|
||||||
|
mocker.patch('freqtrade.worker.Worker._worker', worker_mock)
|
||||||
mocker.patch(
|
mocker.patch(
|
||||||
'freqtrade.configuration.Configuration._load_config_file',
|
'freqtrade.configuration.Configuration._load_config_file',
|
||||||
lambda *args, **kwargs: default_conf
|
lambda *args, **kwargs: default_conf
|
||||||
)
|
)
|
||||||
|
reconfigure_mock = mocker.patch('freqtrade.main.Worker._reconfigure', MagicMock())
|
||||||
|
|
||||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||||
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
||||||
|
|
||||||
# Raise exception as side effect to avoid endless loop
|
args = Arguments(['-c', 'config.json.example'], '').get_parsed_arg()
|
||||||
reconfigure_mock = mocker.patch(
|
worker = Worker(args=args, config=default_conf)
|
||||||
'freqtrade.main.Worker._reconfigure', MagicMock(side_effect=Exception)
|
|
||||||
)
|
|
||||||
|
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
main(['-c', 'config.json.example'])
|
main(['-c', 'config.json.example'])
|
||||||
|
|
||||||
assert reconfigure_mock.call_count == 1
|
|
||||||
assert log_has('Using config: config.json.example ...', caplog.record_tuples)
|
assert log_has('Using config: config.json.example ...', caplog.record_tuples)
|
||||||
|
assert worker_mock.call_count == 4
|
||||||
|
assert reconfigure_mock.call_count == 1
|
||||||
|
assert isinstance(worker.freqtrade, FreqtradeBot)
|
||||||
|
|
||||||
|
|
||||||
def test_reconfigure(mocker, default_conf) -> None:
|
def test_reconfigure(mocker, default_conf) -> None:
|
||||||
|
@ -39,7 +39,7 @@ class Worker(object):
|
|||||||
logger.debug("sd_notify: READY=1")
|
logger.debug("sd_notify: READY=1")
|
||||||
self._sd_notify.notify("READY=1")
|
self._sd_notify.notify("READY=1")
|
||||||
|
|
||||||
def _init(self, reconfig: bool):
|
def _init(self, reconfig: bool) -> None:
|
||||||
"""
|
"""
|
||||||
Also called from the _reconfigure() method (with reconfig=True).
|
Also called from the _reconfigure() method (with reconfig=True).
|
||||||
"""
|
"""
|
||||||
@ -63,17 +63,17 @@ class Worker(object):
|
|||||||
return self.freqtrade.state
|
return self.freqtrade.state
|
||||||
|
|
||||||
@state.setter
|
@state.setter
|
||||||
def state(self, value: State):
|
def state(self, value: State) -> None:
|
||||||
self.freqtrade.state = value
|
self.freqtrade.state = value
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> None:
|
||||||
state = None
|
state = None
|
||||||
while True:
|
while True:
|
||||||
state = self._worker(old_state=state)
|
state = self._worker(old_state=state)
|
||||||
if state == State.RELOAD_CONF:
|
if state == State.RELOAD_CONF:
|
||||||
self.freqtrade = self._reconfigure()
|
self._reconfigure()
|
||||||
|
|
||||||
def _worker(self, old_state: State, throttle_secs: Optional[float] = None) -> State:
|
def _worker(self, old_state: Optional[State], throttle_secs: Optional[float] = None) -> State:
|
||||||
"""
|
"""
|
||||||
Trading routine that must be run at each loop
|
Trading routine that must be run at each loop
|
||||||
:param old_state: the previous service state from the previous call
|
:param old_state: the previous service state from the previous call
|
||||||
@ -148,7 +148,7 @@ class Worker(object):
|
|||||||
# state_changed = True
|
# state_changed = True
|
||||||
return state_changed
|
return state_changed
|
||||||
|
|
||||||
def _reconfigure(self):
|
def _reconfigure(self) -> None:
|
||||||
"""
|
"""
|
||||||
Cleans up current freqtradebot instance, reloads the configuration and
|
Cleans up current freqtradebot instance, reloads the configuration and
|
||||||
replaces it with the new instance
|
replaces it with the new instance
|
||||||
@ -174,7 +174,7 @@ class Worker(object):
|
|||||||
logger.debug("sd_notify: READY=1")
|
logger.debug("sd_notify: READY=1")
|
||||||
self._sd_notify.notify("READY=1")
|
self._sd_notify.notify("READY=1")
|
||||||
|
|
||||||
def exit(self):
|
def exit(self) -> None:
|
||||||
# Tell systemd that we are exiting now
|
# Tell systemd that we are exiting now
|
||||||
if self._sd_notify:
|
if self._sd_notify:
|
||||||
logger.debug("sd_notify: STOPPING=1")
|
logger.debug("sd_notify: STOPPING=1")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# requirements without requirements installable via conda
|
# requirements without requirements installable via conda
|
||||||
# mainly used for Raspberry pi installs
|
# mainly used for Raspberry pi installs
|
||||||
ccxt==1.18.489
|
ccxt==1.18.496
|
||||||
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
|
@ -1,5 +1,5 @@
|
|||||||
# Load common requirements
|
# Load common requirements
|
||||||
-r requirements-pi.txt
|
-r requirements-common.txt
|
||||||
|
|
||||||
numpy==1.16.3
|
numpy==1.16.3
|
||||||
pandas==0.24.2
|
pandas==0.24.2
|
||||||
|
Loading…
Reference in New Issue
Block a user