Merge branch 'develop' into tsl_on_exchange

This commit is contained in:
misagh
2019-01-08 15:33:32 +01:00
13 changed files with 174 additions and 104 deletions

View File

@@ -124,9 +124,6 @@ class Configuration(object):
if self.args.db_url and self.args.db_url != constants.DEFAULT_DB_PROD_URL:
config.update({'db_url': self.args.db_url})
logger.info('Parameter --db-url detected ...')
else:
# Set default here
config.update({'db_url': constants.DEFAULT_DB_PROD_URL})
if config.get('dry_run', False):
logger.info('Dry run is enabled')

View File

@@ -59,7 +59,7 @@ class Edge():
# checking max_open_trades. it should be -1 as with Edge
# the number of trades is determined by position size
if self.config['max_open_trades'] != -1:
if self.config['max_open_trades'] != float('inf'):
logger.critical('max_open_trades should be -1 in config !')
if self.config['stake_amount'] != constants.UNLIMITED_STAKE_AMOUNT:

View File

@@ -38,60 +38,43 @@ class StrategyResolver(IResolver):
self.strategy: IStrategy = self._load_strategy(strategy_name,
config=config,
extra_dir=config.get('strategy_path'))
# Set attributes
# Check if we need to override configuration
if 'minimal_roi' in config:
self.strategy.minimal_roi = config['minimal_roi']
logger.info("Override strategy 'minimal_roi' with value in config file: %s.",
config['minimal_roi'])
else:
config['minimal_roi'] = self.strategy.minimal_roi
attributes = ["minimal_roi",
"ticker_interval",
"stoploss",
"trailing_stop",
"trailing_stop_positive",
"trailing_stop_positive_offset",
"process_only_new_candles",
"order_types",
"order_time_in_force"
]
for attribute in attributes:
self._override_attribute_helper(config, attribute)
if 'stoploss' in config:
self.strategy.stoploss = config['stoploss']
logger.info(
"Override strategy 'stoploss' with value in config file: %s.", config['stoploss']
)
else:
config['stoploss'] = self.strategy.stoploss
# Loop this list again to have output combined
for attribute in attributes:
if attribute in config:
logger.info("Strategy using %s: %s", attribute, config[attribute])
if 'ticker_interval' in config:
self.strategy.ticker_interval = config['ticker_interval']
logger.info(
"Override strategy 'ticker_interval' with value in config file: %s.",
config['ticker_interval']
)
else:
config['ticker_interval'] = self.strategy.ticker_interval
# Sort and apply type conversions
self.strategy.minimal_roi = OrderedDict(sorted(
{int(key): value for (key, value) in self.strategy.minimal_roi.items()}.items(),
key=lambda t: t[0]))
self.strategy.stoploss = float(self.strategy.stoploss)
if 'process_only_new_candles' in config:
self.strategy.process_only_new_candles = config['process_only_new_candles']
logger.info(
"Override process_only_new_candles 'process_only_new_candles' "
"with value in config file: %s.", config['process_only_new_candles']
)
else:
config['process_only_new_candles'] = self.strategy.process_only_new_candles
self._strategy_sanity_validations()
if 'order_types' in config:
self.strategy.order_types = config['order_types']
logger.info(
"Override strategy 'order_types' with value in config file: %s.",
config['order_types']
)
else:
config['order_types'] = self.strategy.order_types
if 'order_time_in_force' in config:
self.strategy.order_time_in_force = config['order_time_in_force']
logger.info(
"Override strategy 'order_time_in_force' with value in config file: %s.",
config['order_time_in_force']
)
else:
config['order_time_in_force'] = self.strategy.order_time_in_force
def _override_attribute_helper(self, config, attribute: str):
if attribute in config:
setattr(self.strategy, attribute, config[attribute])
logger.info("Override strategy '%s' with value in config file: %s.",
attribute, config[attribute])
elif hasattr(self.strategy, attribute):
config[attribute] = getattr(self.strategy, attribute)
def _strategy_sanity_validations(self):
if not all(k in self.strategy.order_types for k in constants.REQUIRED_ORDERTYPES):
raise ImportError(f"Impossible to load Strategy '{self.strategy.__class__.__name__}'. "
f"Order-types mapping is incomplete.")
@@ -100,12 +83,6 @@ class StrategyResolver(IResolver):
raise ImportError(f"Impossible to load Strategy '{self.strategy.__class__.__name__}'. "
f"Order-time-in-force mapping is incomplete.")
# Sort and apply type conversions
self.strategy.minimal_roi = OrderedDict(sorted(
{int(key): value for (key, value) in self.strategy.minimal_roi.items()}.items(),
key=lambda t: t[0]))
self.strategy.stoploss = float(self.strategy.stoploss)
def _load_strategy(
self, strategy_name: str, config: dict, extra_dir: Optional[str] = None) -> IStrategy:
"""

View File

@@ -67,6 +67,11 @@ class IStrategy(ABC):
# associated stoploss
stoploss: float
# trailing stoploss
trailing_stop: bool = False
trailing_stop_positive: float
trailing_stop_positive_offset: float
# associated ticker interval
ticker_interval: str

View File

@@ -150,6 +150,45 @@ def test_strategy_override_stoploss(caplog):
) in caplog.record_tuples
def test_strategy_override_trailing_stop(caplog):
caplog.set_level(logging.INFO)
config = {
'strategy': 'DefaultStrategy',
'trailing_stop': True
}
resolver = StrategyResolver(config)
assert resolver.strategy.trailing_stop
assert isinstance(resolver.strategy.trailing_stop, bool)
assert ('freqtrade.resolvers.strategy_resolver',
logging.INFO,
"Override strategy 'trailing_stop' with value in config file: True."
) in caplog.record_tuples
def test_strategy_override_trailing_stop_positive(caplog):
caplog.set_level(logging.INFO)
config = {
'strategy': 'DefaultStrategy',
'trailing_stop_positive': -0.1,
'trailing_stop_positive_offset': -0.2
}
resolver = StrategyResolver(config)
assert resolver.strategy.trailing_stop_positive == -0.1
assert ('freqtrade.resolvers.strategy_resolver',
logging.INFO,
"Override strategy 'trailing_stop_positive' with value in config file: -0.1."
) in caplog.record_tuples
assert resolver.strategy.trailing_stop_positive_offset == -0.2
assert ('freqtrade.resolvers.strategy_resolver',
logging.INFO,
"Override strategy 'trailing_stop_positive' with value in config file: -0.1."
) in caplog.record_tuples
def test_strategy_override_ticker_interval(caplog):
caplog.set_level(logging.INFO)
@@ -178,8 +217,7 @@ def test_strategy_override_process_only_new_candles(caplog):
assert resolver.strategy.process_only_new_candles
assert ('freqtrade.resolvers.strategy_resolver',
logging.INFO,
"Override process_only_new_candles 'process_only_new_candles' "
"with value in config file: True."
"Override strategy 'process_only_new_candles' with value in config file: True."
) in caplog.record_tuples

View File

@@ -73,7 +73,6 @@ def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) ->
args = Arguments([], '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
print(validated_conf)
assert validated_conf['max_open_trades'] > 999999999
assert validated_conf['max_open_trades'] == float('inf')
@@ -125,6 +124,43 @@ def test_load_config_with_params(default_conf, mocker) -> None:
assert validated_conf.get('strategy_path') == '/some/path'
assert validated_conf.get('db_url') == 'sqlite:///someurl'
# Test conf provided db_url prod
conf = default_conf.copy()
conf["dry_run"] = False
conf["db_url"] = "sqlite:///path/to/db.sqlite"
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
read_data=json.dumps(conf)
))
arglist = [
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('db_url') == "sqlite:///path/to/db.sqlite"
# Test conf provided db_url dry_run
conf = default_conf.copy()
conf["dry_run"] = True
conf["db_url"] = "sqlite:///path/to/db.sqlite"
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
read_data=json.dumps(conf)
))
arglist = [
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('db_url') == "sqlite:///path/to/db.sqlite"
# Test args provided db_url prod
conf = default_conf.copy()
conf["dry_run"] = False
del conf["db_url"]
@@ -142,7 +178,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
validated_conf = configuration.load_config()
assert validated_conf.get('db_url') == DEFAULT_DB_PROD_URL
# Test dry=run with ProdURL
# Test args provided db_url dry_run
conf = default_conf.copy()
conf["dry_run"] = True
conf["db_url"] = DEFAULT_DB_PROD_URL