Merge develop

This commit is contained in:
hroff-1902
2019-12-05 01:08:38 +03:00
46 changed files with 927 additions and 414 deletions

View File

@@ -13,7 +13,8 @@ from pandas import DataFrame
from tabulate import tabulate
from freqtrade import OperationalException
from freqtrade.configuration import TimeRange, remove_credentials
from freqtrade.configuration import (TimeRange, remove_credentials,
validate_config_consistency)
from freqtrade.data import history
from freqtrade.data.dataprovider import DataProvider
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
@@ -75,10 +76,12 @@ class Backtesting:
stratconf = deepcopy(self.config)
stratconf['strategy'] = strat
self.strategylist.append(StrategyResolver(stratconf).strategy)
validate_config_consistency(stratconf)
else:
# No strategy list specified, only one strategy
self.strategylist.append(StrategyResolver(self.config).strategy)
validate_config_consistency(self.config)
if "ticker_interval" not in self.config:
raise OperationalException("Ticker-interval needs to be set in either configuration "

View File

@@ -9,7 +9,8 @@ from typing import Any, Dict
from tabulate import tabulate
from freqtrade import constants
from freqtrade.configuration import TimeRange, remove_credentials
from freqtrade.configuration import (TimeRange, remove_credentials,
validate_config_consistency)
from freqtrade.edge import Edge
from freqtrade.exchange import Exchange
from freqtrade.resolvers import StrategyResolver
@@ -35,6 +36,8 @@ class EdgeCli:
self.exchange = Exchange(self.config)
self.strategy = StrategyResolver(self.config).strategy
validate_config_consistency(self.config)
self.edge = Edge(config, self.exchange, self.strategy)
# Set refresh_pairs to false for edge-cli (it must be true for edge)
self.edge._refresh_pairs = False

View File

@@ -175,6 +175,9 @@ class Hyperopt:
if self.has_space('stoploss'):
result['stoploss'] = {p.name: params.get(p.name)
for p in self.hyperopt_space('stoploss')}
if self.has_space('trailing'):
result['trailing'] = {p.name: params.get(p.name)
for p in self.hyperopt_space('trailing')}
return result
@@ -196,7 +199,7 @@ class Hyperopt:
if print_json:
result_dict: Dict = {}
for s in ['buy', 'sell', 'roi', 'stoploss']:
for s in ['buy', 'sell', 'roi', 'stoploss', 'trailing']:
Hyperopt._params_update_for_json(result_dict, params, s)
print(rapidjson.dumps(result_dict, default=str, number_mode=rapidjson.NM_NATIVE))
@@ -205,6 +208,7 @@ class Hyperopt:
Hyperopt._params_pretty_print(params, 'sell', "Sell hyperspace params:")
Hyperopt._params_pretty_print(params, 'roi', "ROI table:")
Hyperopt._params_pretty_print(params, 'stoploss', "Stoploss:")
Hyperopt._params_pretty_print(params, 'trailing', "Trailing stop:")
@staticmethod
def _params_update_for_json(result_dict, params, space: str):
@@ -220,7 +224,7 @@ class Hyperopt:
result_dict['minimal_roi'] = OrderedDict(
(str(k), v) for k, v in space_params.items()
)
else: # 'stoploss'
else: # 'stoploss', 'trailing'
result_dict.update(space_params)
@staticmethod
@@ -285,9 +289,13 @@ class Hyperopt:
def has_space(self, space: str) -> bool:
"""
Tell if a space value is contained in the configuration
Tell if the space value is contained in the configuration
"""
return any(s in self.config['spaces'] for s in [space, 'all'])
# The 'trailing' space is not included in the 'default' set of spaces
if space == 'trailing':
return any(s in self.config['spaces'] for s in [space, 'all'])
else:
return any(s in self.config['spaces'] for s in [space, 'all', 'default'])
def hyperopt_space(self, space: Optional[str] = None) -> List[Dimension]:
"""
@@ -297,18 +305,27 @@ class Hyperopt:
for all hyperspaces used.
"""
spaces: List[Dimension] = []
if space == 'buy' or (space is None and self.has_space('buy')):
logger.debug("Hyperopt has 'buy' space")
spaces += self.custom_hyperopt.indicator_space()
if space == 'sell' or (space is None and self.has_space('sell')):
logger.debug("Hyperopt has 'sell' space")
spaces += self.custom_hyperopt.sell_indicator_space()
if space == 'roi' or (space is None and self.has_space('roi')):
logger.debug("Hyperopt has 'roi' space")
spaces += self.custom_hyperopt.roi_space()
if space == 'stoploss' or (space is None and self.has_space('stoploss')):
logger.debug("Hyperopt has 'stoploss' space")
spaces += self.custom_hyperopt.stoploss_space()
if space == 'trailing' or (space is None and self.has_space('trailing')):
logger.debug("Hyperopt has 'trailing' space")
spaces += self.custom_hyperopt.trailing_space()
return spaces
def generate_optimizer(self, raw_params: List[Any], iteration=None) -> Dict:
@@ -334,6 +351,15 @@ class Hyperopt:
if self.has_space('stoploss'):
self.backtesting.strategy.stoploss = params_dict['stoploss']
if self.has_space('trailing'):
self.backtesting.strategy.trailing_stop = params_dict['trailing_stop']
self.backtesting.strategy.trailing_stop_positive = \
params_dict['trailing_stop_positive']
self.backtesting.strategy.trailing_stop_positive_offset = \
params_dict['trailing_stop_positive_offset']
self.backtesting.strategy.trailing_only_offset_is_reached = \
params_dict['trailing_only_offset_is_reached']
processed = load(self.tickerdata_pickle)
min_date, max_date = get_timeframe(processed)

View File

@@ -8,7 +8,7 @@ import math
from abc import ABC
from typing import Dict, Any, Callable, List
from skopt.space import Dimension, Integer, Real
from skopt.space import Categorical, Dimension, Integer, Real
from freqtrade import OperationalException
from freqtrade.exchange import timeframe_to_minutes
@@ -174,6 +174,27 @@ class IHyperOpt(ABC):
Real(-0.35, -0.02, name='stoploss'),
]
@staticmethod
def trailing_space() -> List[Dimension]:
"""
Create a trailing stoploss space.
You may override it in your custom Hyperopt class.
"""
return [
# It was decided to always set trailing_stop is to True if the 'trailing' hyperspace
# is used. Otherwise hyperopt will vary other parameters that won't have effect if
# trailing_stop is set False.
# This parameter is included into the hyperspace dimensions rather than assigning
# it explicitly in the code in order to have it printed in the results along with
# other 'trailing' hyperspace parameters.
Categorical([True], name='trailing_stop'),
Real(0.02, 0.35, name='trailing_stop_positive'),
Real(0.01, 0.1, name='trailing_stop_positive_offset'),
Categorical([True, False], name='trailing_only_offset_is_reached'),
]
# This is needed for proper unpickling the class attribute ticker_interval
# which is set to the actual value by the resolver.
# Why do I still need such shamanic mantras in modern python?