diff --git a/docs/bot-usage.md b/docs/bot-usage.md index cb98e1ea5..b215d7b7c 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -26,7 +26,8 @@ optional arguments: --version show program's version number and exit -c PATH, --config PATH Specify configuration file (default: None). Multiple - --config options may be used. + --config options may be used. Can be set to '-' to + read config from stdin. -d PATH, --datadir PATH Path to backtest data. -s NAME, --strategy NAME diff --git a/docs/webhook-config.md b/docs/webhook-config.md index 811b57f9b..112f8a77e 100644 --- a/docs/webhook-config.md +++ b/docs/webhook-config.md @@ -43,6 +43,7 @@ Possible parameters are: * `stake_amount` * `stake_currency` * `fiat_currency` +* `order_type` ### Webhooksell @@ -61,6 +62,7 @@ Possible parameters are: * `stake_currency` * `fiat_currency` * `sell_reason` +* `order_type` ### Webhookstatus diff --git a/freqtrade/arguments.py b/freqtrade/arguments.py index 3f21709c9..3075dd0fe 100644 --- a/freqtrade/arguments.py +++ b/freqtrade/arguments.py @@ -33,7 +33,8 @@ class Arguments(object): self.parser = argparse.ArgumentParser(description=description) def _load_args(self) -> None: - self.common_args_parser() + self.common_options() + self.main_options() self._build_subcommands() def get_parsed_arg(self) -> argparse.Namespace: @@ -60,62 +61,66 @@ class Arguments(object): return parsed_arg - def common_args_parser(self) -> None: + def common_options(self) -> None: """ - Parses given common arguments and returns them as a parsed object. + Parses arguments that are common for the main Freqtrade, all subcommands and scripts. """ - self.parser.add_argument( + parser = self.parser + + parser.add_argument( '-v', '--verbose', help='Verbose mode (-vv for more, -vvv to get all messages).', action='count', dest='loglevel', default=0, ) - self.parser.add_argument( + parser.add_argument( '--logfile', help='Log to the file specified', dest='logfile', - type=str, - metavar='FILE' + metavar='FILE', ) - self.parser.add_argument( + parser.add_argument( '--version', action='version', version=f'%(prog)s {__version__}' ) - self.parser.add_argument( + parser.add_argument( '-c', '--config', - help='Specify configuration file (default: %(default)s). ' - 'Multiple --config options may be used.', + help="Specify configuration file (default: %(default)s). " + "Multiple --config options may be used. " + "Can be set to '-' to read config from stdin.", dest='config', action='append', - type=str, metavar='PATH', ) - self.parser.add_argument( + parser.add_argument( '-d', '--datadir', help='Path to backtest data.', dest='datadir', - default=None, - type=str, metavar='PATH', ) - self.parser.add_argument( + + def main_options(self) -> None: + """ + Parses arguments for the main Freqtrade. + """ + parser = self.parser + + parser.add_argument( '-s', '--strategy', help='Specify strategy class name (default: %(default)s).', dest='strategy', default='DefaultStrategy', - type=str, metavar='NAME', ) - self.parser.add_argument( + parser.add_argument( '--strategy-path', help='Specify additional strategy lookup path.', dest='strategy_path', - type=str, metavar='PATH', ) - self.parser.add_argument( + parser.add_argument( '--dynamic-whitelist', help='Dynamically generate and update whitelist' ' based on 24h BaseVolume (default: %(const)s).' @@ -126,52 +131,46 @@ class Arguments(object): metavar='INT', nargs='?', ) - self.parser.add_argument( + parser.add_argument( '--db-url', help='Override trades database URL, this is useful if dry_run is enabled' ' or in custom deployments (default: %(default)s).', dest='db_url', - type=str, metavar='PATH', ) - self.parser.add_argument( + parser.add_argument( '--sd-notify', help='Notify systemd service manager.', action='store_true', dest='sd_notify', ) - @staticmethod - def optimizer_shared_options(parser: argparse.ArgumentParser) -> None: + def common_optimize_options(self, subparser: argparse.ArgumentParser = None) -> None: """ - Parses given common arguments for Backtesting, Edge and Hyperopt modules. + Parses arguments common for Backtesting, Edge and Hyperopt modules. :param parser: - :return: """ + parser = subparser or self.parser + parser.add_argument( '-i', '--ticker-interval', help='Specify ticker interval (1m, 5m, 30m, 1h, 1d).', dest='ticker_interval', - type=str, ) parser.add_argument( '--timerange', help='Specify what timerange of data to use.', - default=None, - type=str, dest='timerange', ) parser.add_argument( '--max_open_trades', help='Specify max_open_trades to use.', - default=None, type=int, dest='max_open_trades', ) parser.add_argument( '--stake_amount', help='Specify stake_amount.', - default=None, type=float, dest='stake_amount', ) @@ -184,11 +183,12 @@ class Arguments(object): dest='refresh_pairs', ) - @staticmethod - def backtesting_options(parser: argparse.ArgumentParser) -> None: + def backtesting_options(self, subparser: argparse.ArgumentParser = None) -> None: """ Parses given arguments for Backtesting module. """ + parser = subparser or self.parser + parser.add_argument( '--eps', '--enable-position-stacking', help='Allow buying the same pair multiple times (position stacking).', @@ -224,8 +224,6 @@ class Arguments(object): '--export', help='Export backtest results, argument are: trades. ' 'Example --export=trades', - type=str, - default=None, dest='export', ) parser.add_argument( @@ -234,37 +232,36 @@ class Arguments(object): requires --export to be set as well\ Example --export-filename=user_data/backtest_data/backtest_today.json\ (default: %(default)s)', - type=str, default=os.path.join('user_data', 'backtest_data', 'backtest-result.json'), dest='exportfilename', metavar='PATH', ) - @staticmethod - def edge_options(parser: argparse.ArgumentParser) -> None: + def edge_options(self, subparser: argparse.ArgumentParser = None) -> None: """ Parses given arguments for Edge module. """ + parser = subparser or self.parser + parser.add_argument( '--stoplosses', help='Defines a range of stoploss against which edge will assess the strategy ' 'the format is "min,max,step" (without any space).' 'example: --stoplosses=-0.01,-0.1,-0.001', - type=str, dest='stoploss_range', ) - @staticmethod - def hyperopt_options(parser: argparse.ArgumentParser) -> None: + def hyperopt_options(self, subparser: argparse.ArgumentParser = None) -> None: """ Parses given arguments for Hyperopt module. """ + parser = subparser or self.parser + parser.add_argument( '--customhyperopt', help='Specify hyperopt class name (default: %(default)s).', dest='hyperopt', default=constants.DEFAULT_HYPEROPT, - type=str, metavar='NAME', ) parser.add_argument( @@ -321,7 +318,6 @@ class Arguments(object): '--random-state', help='Set random state to some positive integer for reproducible hyperopt results.', dest='hyperopt_random_state', - default=None, type=Arguments.check_int_positive, metavar='INT', ) @@ -335,11 +331,12 @@ class Arguments(object): metavar='INT', ) - @staticmethod - def list_exchanges_options(parser: argparse.ArgumentParser) -> None: + def list_exchanges_options(self, subparser: argparse.ArgumentParser = None) -> None: """ Parses given arguments for the list-exchanges command. """ + parser = subparser or self.parser + parser.add_argument( '-1', '--one-column', help='Print exchanges in one column', @@ -349,7 +346,7 @@ class Arguments(object): def _build_subcommands(self) -> None: """ - Builds and attaches all subcommands + Builds and attaches all subcommands. :return: None """ from freqtrade.optimize import start_backtesting, start_hyperopt, start_edge @@ -360,19 +357,19 @@ class Arguments(object): # Add backtesting subcommand backtesting_cmd = subparsers.add_parser('backtesting', help='Backtesting module.') backtesting_cmd.set_defaults(func=start_backtesting) - self.optimizer_shared_options(backtesting_cmd) + self.common_optimize_options(backtesting_cmd) self.backtesting_options(backtesting_cmd) # Add edge subcommand edge_cmd = subparsers.add_parser('edge', help='Edge module.') edge_cmd.set_defaults(func=start_edge) - self.optimizer_shared_options(edge_cmd) + self.common_optimize_options(edge_cmd) self.edge_options(edge_cmd) # Add hyperopt subcommand hyperopt_cmd = subparsers.add_parser('hyperopt', help='Hyperopt module.') hyperopt_cmd.set_defaults(func=start_hyperopt) - self.optimizer_shared_options(hyperopt_cmd) + self.common_optimize_options(hyperopt_cmd) self.hyperopt_options(hyperopt_cmd) # Add list-exchanges subcommand @@ -437,69 +434,43 @@ class Arguments(object): ) return uint - def scripts_options(self) -> None: + def common_scripts_options(self, subparser: argparse.ArgumentParser = None) -> None: """ - Parses given arguments for scripts. + Parses arguments common for scripts. """ - self.parser.add_argument( + parser = subparser or self.parser + + parser.add_argument( '-p', '--pairs', help='Show profits for only this pairs. Pairs are comma-separated.', dest='pairs', - default=None ) def download_data_options(self) -> None: """ - Parses given arguments for testdata download + Parses given arguments for testdata download script """ - self.parser.add_argument( - '-v', '--verbose', - help='Verbose mode (-vv for more, -vvv to get all messages).', - action='count', - dest='loglevel', - default=0, - ) - self.parser.add_argument( - '--logfile', - help='Log to the file specified', - dest='logfile', - type=str, - metavar='FILE', - ) - self.parser.add_argument( - '-c', '--config', - help='Specify configuration file (default: %(default)s). ' - 'Multiple --config options may be used.', - dest='config', - action='append', - type=str, - metavar='PATH', - ) - self.parser.add_argument( - '-d', '--datadir', - help='Path to backtest data.', - dest='datadir', - metavar='PATH', - ) - self.parser.add_argument( + parser = self.parser + + parser.add_argument( '--pairs-file', help='File containing a list of pairs to download.', dest='pairs_file', metavar='FILE', ) - self.parser.add_argument( + parser.add_argument( '--days', help='Download data for given number of days.', dest='days', type=Arguments.check_int_positive, metavar='INT', ) - self.parser.add_argument( + parser.add_argument( '--exchange', help='Exchange name (default: %(default)s). Only valid if no config is provided.', dest='exchange', ) - self.parser.add_argument( + parser.add_argument( '-t', '--timeframes', help='Specify which tickers to download. Space separated list. \ Default: %(default)s.', @@ -508,7 +479,7 @@ class Arguments(object): nargs='+', dest='timeframes', ) - self.parser.add_argument( + parser.add_argument( '--erase', help='Clean all existing data for the selected exchange/pairs/timeframes.', dest='erase', @@ -517,33 +488,26 @@ class Arguments(object): def plot_dataframe_options(self) -> None: """ - Parses given arguments for plot_dataframe + Parses given arguments for plot dataframe script """ - self.parser.add_argument( - '-p', '--pairs', - help='Show profits for only this pairs. Pairs are comma-separated.', - dest='pairs', - required=True, - default=None - ) - self.parser.add_argument( + parser = self.parser + + parser.add_argument( '--indicators1', help='Set indicators from your strategy you want in the first row of the graph. ' - 'Separate them with a comma. E.g: ema3,ema5 (default: %(default)s)', - type=str, + 'Separate them with a coma. E.g: ema3,ema5 (default: %(default)s)', default='sma,ema3,ema5', dest='indicators1', ) - self.parser.add_argument( + parser.add_argument( '--indicators2', help='Set indicators from your strategy you want in the third row of the graph. ' - 'Separate them with a comma. E.g: macd,fastd,fastk (default: %(default)s)', - type=str, + 'Separate them with a coma. E.g: fastd,fastk (default: %(default)s)', default='macd,macdsignal', dest='indicators2', ) - self.parser.add_argument( + parser.add_argument( '--plot-limit', help='Specify tick limit for plotting - too high values cause huge files - ' 'Default: %(default)s', diff --git a/freqtrade/configuration.py b/freqtrade/configuration.py index c63e99318..b2c35c977 100644 --- a/freqtrade/configuration.py +++ b/freqtrade/configuration.py @@ -34,13 +34,17 @@ def set_loggers(log_level: int = 0) -> None: logging.getLogger('telegram').setLevel(logging.INFO) -def _extend_with_default(validator_class): - validate_properties = validator_class.VALIDATORS["properties"] +def _extend_validator(validator_class): + """ + Extended validator for the Freqtrade configuration JSON Schema. + Currently it only handles defaults for subschemas. + """ + validate_properties = validator_class.VALIDATORS['properties'] def set_defaults(validator, properties, instance, schema): for prop, subschema in properties.items(): - if "default" in subschema: - instance.setdefault(prop, subschema["default"]) + if 'default' in subschema: + instance.setdefault(prop, subschema['default']) for error in validate_properties( validator, properties, instance, schema, @@ -48,11 +52,11 @@ def _extend_with_default(validator_class): yield error return validators.extend( - validator_class, {"properties": set_defaults}, + validator_class, {'properties': set_defaults} ) -ValidatorWithDefaults = _extend_with_default(Draft4Validator) +FreqtradeValidator = _extend_validator(Draft4Validator) class Configuration(object): @@ -75,6 +79,7 @@ class Configuration(object): # Now expecting a list of config filenames here, not a string for path in self.args.config: logger.info('Using config: %s ...', path) + # Merge config options, overwriting old values config = deep_merge_dicts(self._load_config_file(path), config) @@ -117,7 +122,8 @@ class Configuration(object): :return: configuration as dictionary """ try: - with open(path) as file: + # Read config from stdin if requested in the options + with open(path) if path != '-' else sys.stdin as file: conf = json.load(file) except FileNotFoundError: raise OperationalException( @@ -362,7 +368,7 @@ class Configuration(object): :return: Returns the config if valid, otherwise throw an exception """ try: - ValidatorWithDefaults(constants.CONF_SCHEMA).validate(conf) + FreqtradeValidator(constants.CONF_SCHEMA).validate(conf) return conf except ValidationError as exception: logger.critical( diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 471e9d218..305a97ba6 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -205,19 +205,19 @@ class FreqtradeBot(object): else: stake_amount = self.config['stake_amount'] - avaliable_amount = self.wallets.get_free(self.config['stake_currency']) + available_amount = self.wallets.get_free(self.config['stake_currency']) if stake_amount == constants.UNLIMITED_STAKE_AMOUNT: open_trades = len(Trade.get_open_trades()) if open_trades >= self.config['max_open_trades']: logger.warning('Can\'t open a new trade: max number of trades is reached') return None - return avaliable_amount / (self.config['max_open_trades'] - open_trades) + return available_amount / (self.config['max_open_trades'] - open_trades) # Check if stake_amount is fulfilled - if avaliable_amount < stake_amount: + if available_amount < stake_amount: raise DependencyException( - f"Available balance({avaliable_amount} {self.config['stake_currency']}) is " + f"Available balance({available_amount} {self.config['stake_currency']}) is " f"lower than stake amount({stake_amount} {self.config['stake_currency']})" ) @@ -345,8 +345,8 @@ class FreqtradeBot(object): return False amount = stake_amount / buy_limit_requested - - order = self.exchange.buy(pair=pair, ordertype=self.strategy.order_types['buy'], + order_type = self.strategy.order_types['buy'] + order = self.exchange.buy(pair=pair, ordertype=order_type, amount=amount, rate=buy_limit_requested, time_in_force=time_in_force) order_id = order['id'] @@ -356,7 +356,6 @@ class FreqtradeBot(object): buy_limit_filled_price = buy_limit_requested if order_status == 'expired' or order_status == 'rejected': - order_type = self.strategy.order_types['buy'] order_tif = self.strategy.order_time_in_force['buy'] # return false if the order is not filled @@ -390,6 +389,7 @@ class FreqtradeBot(object): 'exchange': self.exchange.name.capitalize(), 'pair': pair_s, 'limit': buy_limit_filled_price, + 'order_type': order_type, 'stake_amount': stake_amount, 'stake_currency': stake_currency, 'fiat_currency': fiat_currency @@ -875,6 +875,7 @@ class FreqtradeBot(object): 'pair': trade.pair, 'gain': gain, 'limit': trade.close_rate_requested, + 'order_type': self.strategy.order_types['sell'], 'amount': trade.amount, 'open_rate': trade.open_rate, 'current_rate': current_rate, diff --git a/freqtrade/optimize/__init__.py b/freqtrade/optimize/__init__.py index 475aaa82f..8b548eefe 100644 --- a/freqtrade/optimize/__init__.py +++ b/freqtrade/optimize/__init__.py @@ -5,8 +5,9 @@ from typing import Any, Dict from filelock import FileLock, Timeout from freqtrade import DependencyException, constants -from freqtrade.configuration import Configuration from freqtrade.state import RunMode +from freqtrade.utils import setup_utils_configuration + logger = logging.getLogger(__name__) @@ -17,12 +18,7 @@ def setup_configuration(args: Namespace, method: RunMode) -> Dict[str, Any]: :param args: Cli args from Arguments() :return: Configuration """ - configuration = Configuration(args, method) - config = configuration.load_config() - - # Ensure we do not use Exchange credentials - config['exchange']['key'] = '' - config['exchange']['secret'] = '' + config = setup_utils_configuration(args, method) if method == RunMode.BACKTEST: if config['stake_amount'] == constants.UNLIMITED_STAKE_AMOUNT: diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 497c117ac..3eb060074 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -132,7 +132,7 @@ class Telegram(RPC): msg['stake_amount_fiat'] = 0 message = ("*{exchange}:* Buying {pair}\n" - "with limit `{limit:.8f}\n" + "at rate `{limit:.8f}\n" "({stake_amount:.6f} {stake_currency}").format(**msg) if msg.get('fiat_currency', None): @@ -144,7 +144,7 @@ class Telegram(RPC): msg['profit_percent'] = round(msg['profit_percent'] * 100, 2) message = ("*{exchange}:* Selling {pair}\n" - "*Limit:* `{limit:.8f}`\n" + "*Rate:* `{limit:.8f}`\n" "*Amount:* `{amount:.8f}`\n" "*Open Rate:* `{open_rate:.8f}`\n" "*Current Rate:* `{current_rate:.8f}`\n" diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 46ef15f56..b34e214af 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -756,6 +756,7 @@ def test_forcesell_handle(default_conf, update, ticker, fee, 'gain': 'profit', 'limit': 1.172e-05, 'amount': 90.99181073703367, + 'order_type': 'limit', 'open_rate': 1.099e-05, 'current_rate': 1.172e-05, 'profit_amount': 6.126e-05, @@ -810,6 +811,7 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, 'gain': 'loss', 'limit': 1.044e-05, 'amount': 90.99181073703367, + 'order_type': 'limit', 'open_rate': 1.099e-05, 'current_rate': 1.044e-05, 'profit_amount': -5.492e-05, @@ -855,6 +857,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker 'gain': 'loss', 'limit': 1.098e-05, 'amount': 90.99181073703367, + 'order_type': 'limit', 'open_rate': 1.099e-05, 'current_rate': 1.098e-05, 'profit_amount': -5.91e-06, @@ -1188,6 +1191,7 @@ def test_send_msg_buy_notification(default_conf, mocker) -> None: 'exchange': 'Bittrex', 'pair': 'ETH/BTC', 'limit': 1.099e-05, + 'order_type': 'limit', 'stake_amount': 0.001, 'stake_amount_fiat': 0.0, 'stake_currency': 'BTC', @@ -1195,7 +1199,7 @@ def test_send_msg_buy_notification(default_conf, mocker) -> None: }) assert msg_mock.call_args[0][0] \ == '*Bittrex:* Buying ETH/BTC\n' \ - 'with limit `0.00001099\n' \ + 'at rate `0.00001099\n' \ '(0.001000 BTC,0.000 USD)`' @@ -1217,6 +1221,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: 'gain': 'loss', 'limit': 3.201e-05, 'amount': 1333.3333333333335, + 'order_type': 'market', 'open_rate': 7.5e-05, 'current_rate': 3.201e-05, 'profit_amount': -0.05746268, @@ -1227,7 +1232,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: }) assert msg_mock.call_args[0][0] \ == ('*Binance:* Selling KEY/ETH\n' - '*Limit:* `0.00003201`\n' + '*Rate:* `0.00003201`\n' '*Amount:* `1333.33333333`\n' '*Open Rate:* `0.00007500`\n' '*Current Rate:* `0.00003201`\n' @@ -1242,6 +1247,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: 'gain': 'loss', 'limit': 3.201e-05, 'amount': 1333.3333333333335, + 'order_type': 'market', 'open_rate': 7.5e-05, 'current_rate': 3.201e-05, 'profit_amount': -0.05746268, @@ -1251,7 +1257,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: }) assert msg_mock.call_args[0][0] \ == ('*Binance:* Selling KEY/ETH\n' - '*Limit:* `0.00003201`\n' + '*Rate:* `0.00003201`\n' '*Amount:* `1333.33333333`\n' '*Open Rate:* `0.00007500`\n' '*Current Rate:* `0.00003201`\n' @@ -1339,6 +1345,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: 'exchange': 'Bittrex', 'pair': 'ETH/BTC', 'limit': 1.099e-05, + 'order_type': 'limit', 'stake_amount': 0.001, 'stake_amount_fiat': 0.0, 'stake_currency': 'BTC', @@ -1346,7 +1353,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: }) assert msg_mock.call_args[0][0] \ == '*Bittrex:* Buying ETH/BTC\n' \ - 'with limit `0.00001099\n' \ + 'at rate `0.00001099\n' \ '(0.001000 BTC)`' @@ -1367,6 +1374,7 @@ def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None: 'gain': 'loss', 'limit': 3.201e-05, 'amount': 1333.3333333333335, + 'order_type': 'limit', 'open_rate': 7.5e-05, 'current_rate': 3.201e-05, 'profit_amount': -0.05746268, @@ -1377,7 +1385,7 @@ def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None: }) assert msg_mock.call_args[0][0] \ == '*Binance:* Selling KEY/ETH\n' \ - '*Limit:* `0.00003201`\n' \ + '*Rate:* `0.00003201`\n' \ '*Amount:* `1333.33333333`\n' \ '*Open Rate:* `0.00007500`\n' \ '*Current Rate:* `0.00003201`\n' \ diff --git a/freqtrade/tests/rpc/test_rpc_webhook.py b/freqtrade/tests/rpc/test_rpc_webhook.py index da7aec0a6..a2dcd9b31 100644 --- a/freqtrade/tests/rpc/test_rpc_webhook.py +++ b/freqtrade/tests/rpc/test_rpc_webhook.py @@ -74,6 +74,7 @@ def test_send_msg(default_conf, mocker): 'gain': "profit", 'limit': 0.005, 'amount': 0.8, + 'order_type': 'limit', 'open_rate': 0.004, 'current_rate': 0.005, 'profit_amount': 0.001, @@ -126,6 +127,7 @@ def test_exception_send_msg(default_conf, mocker, caplog): 'exchange': 'Bittrex', 'pair': 'ETH/BTC', 'limit': 0.005, + 'order_type': 'limit', 'stake_amount': 0.8, 'stake_amount_fiat': 500, 'stake_currency': 'BTC', diff --git a/freqtrade/tests/test_arguments.py b/freqtrade/tests/test_arguments.py index d584a9e01..78ca9d055 100644 --- a/freqtrade/tests/test_arguments.py +++ b/freqtrade/tests/test_arguments.py @@ -47,9 +47,9 @@ def test_parse_args_verbose() -> None: assert args.loglevel == 1 -def test_scripts_options() -> None: +def test_common_scripts_options() -> None: arguments = Arguments(['-p', 'ETH/BTC'], '') - arguments.scripts_options() + arguments.common_scripts_options() args = arguments.get_parsed_arg() assert args.pairs == 'ETH/BTC' @@ -178,6 +178,7 @@ def test_download_data_options() -> None: '--exchange', 'binance' ] arguments = Arguments(args, '') + arguments.common_options() arguments.download_data_options() args = arguments.parse_args() assert args.pairs_file == 'file_with_pairs' diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 6566e4036..65225689b 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1994,6 +1994,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, moc 'gain': 'profit', 'limit': 1.172e-05, 'amount': 90.99181073703367, + 'order_type': 'limit', 'open_rate': 1.099e-05, 'current_rate': 1.172e-05, 'profit_amount': 6.126e-05, @@ -2040,6 +2041,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets, 'gain': 'loss', 'limit': 1.044e-05, 'amount': 90.99181073703367, + 'order_type': 'limit', 'open_rate': 1.099e-05, 'current_rate': 1.044e-05, 'profit_amount': -5.492e-05, @@ -2094,6 +2096,7 @@ def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fe 'gain': 'loss', 'limit': 1.08801e-05, 'amount': 90.99181073703367, + 'order_type': 'limit', 'open_rate': 1.099e-05, 'current_rate': 1.044e-05, 'profit_amount': -1.498e-05, @@ -2265,6 +2268,7 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee, 'gain': 'profit', 'limit': 1.172e-05, 'amount': 90.99181073703367, + 'order_type': 'limit', 'open_rate': 1.099e-05, 'current_rate': 1.172e-05, 'profit_amount': 6.126e-05, @@ -2312,6 +2316,7 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee, 'gain': 'loss', 'limit': 1.044e-05, 'amount': 90.99181073703367, + 'order_type': 'limit', 'open_rate': 1.099e-05, 'current_rate': 1.044e-05, 'profit_amount': -5.492e-05, diff --git a/freqtrade/tests/test_utils.py b/freqtrade/tests/test_utils.py index 7550efb23..a12b709d7 100644 --- a/freqtrade/tests/test_utils.py +++ b/freqtrade/tests/test_utils.py @@ -1,17 +1,18 @@ -from freqtrade.utils import setup_configuration, start_list_exchanges +from freqtrade.utils import setup_utils_configuration, start_list_exchanges from freqtrade.tests.conftest import get_args from freqtrade.state import RunMode import re -def test_setup_configuration(): +def test_setup_utils_configuration(): args = [ '--config', 'config.json.example', ] - config = setup_configuration(get_args(args), RunMode.OTHER) + config = setup_utils_configuration(get_args(args), RunMode.OTHER) assert "exchange" in config + assert config['exchange']['dry_run'] is True assert config['exchange']['key'] == '' assert config['exchange']['secret'] == '' diff --git a/freqtrade/utils.py b/freqtrade/utils.py index 324b54a4e..d550ef43c 100644 --- a/freqtrade/utils.py +++ b/freqtrade/utils.py @@ -10,15 +10,16 @@ from freqtrade.state import RunMode logger = logging.getLogger(__name__) -def setup_configuration(args: Namespace, method: RunMode) -> Dict[str, Any]: +def setup_utils_configuration(args: Namespace, method: RunMode) -> Dict[str, Any]: """ - Prepare the configuration for the Hyperopt module + Prepare the configuration for utils subcommands :param args: Cli args from Arguments() :return: Configuration """ configuration = Configuration(args, method) config = configuration.load_config() + config['exchange']['dry_run'] = True # Ensure we do not use Exchange credentials config['exchange']['key'] = '' config['exchange']['secret'] = '' diff --git a/requirements-common.txt b/requirements-common.txt index 8b44e9d28..ed3f052a9 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,6 +1,6 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs -ccxt==1.18.667 +ccxt==1.18.725 SQLAlchemy==1.3.4 python-telegram-bot==11.1.0 arrow==0.14.2 diff --git a/requirements-dev.txt b/requirements-dev.txt index c8dd8b0b9..ce05b47f0 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,9 +5,9 @@ flake8==3.7.7 flake8-type-annotations==0.1.0 flake8-tidy-imports==2.0.0 -pytest==4.6.2 +pytest==4.6.3 pytest-mock==1.10.4 pytest-asyncio==0.10.0 pytest-cov==2.7.1 -coveralls==1.8.0 +coveralls==1.8.1 mypy==0.701 diff --git a/scripts/download_backtest_data.py b/scripts/download_backtest_data.py index 6263d0e2f..dd4627c14 100755 --- a/scripts/download_backtest_data.py +++ b/scripts/download_backtest_data.py @@ -20,7 +20,8 @@ logger = logging.getLogger('download_backtest_data') DEFAULT_DL_PATH = 'user_data/data' -arguments = Arguments(sys.argv[1:], 'download utility') +arguments = Arguments(sys.argv[1:], 'Download backtest data') +arguments.common_options() arguments.download_data_options() # Do not read the default config if config is not specified diff --git a/scripts/plot_dataframe.py b/scripts/plot_dataframe.py index eebe20be2..a17076085 100755 --- a/scripts/plot_dataframe.py +++ b/scripts/plot_dataframe.py @@ -147,10 +147,12 @@ def plot_parse_args(args: List[str]) -> Dict[str, Any]: :return: args: Array with all arguments """ arguments = Arguments(args, 'Graph dataframe') + arguments.common_options() + arguments.main_options() + arguments.common_optimize_options() + arguments.backtesting_options() + arguments.common_scripts_options() arguments.plot_dataframe_options() - arguments.common_args_parser() - arguments.optimizer_shared_options(arguments.parser) - arguments.backtesting_options(arguments.parser) parsed_args = arguments.parse_args() # Load the configuration diff --git a/scripts/plot_profit.py b/scripts/plot_profit.py index 5f7d42c87..fd98c120c 100755 --- a/scripts/plot_profit.py +++ b/scripts/plot_profit.py @@ -206,10 +206,11 @@ def plot_parse_args(args: List[str]) -> Namespace: :return: args: Array with all arguments """ arguments = Arguments(args, 'Graph profits') - arguments.scripts_options() - arguments.common_args_parser() - arguments.optimizer_shared_options(arguments.parser) - arguments.backtesting_options(arguments.parser) + arguments.common_options() + arguments.main_options() + arguments.common_optimize_options() + arguments.backtesting_options() + arguments.common_scripts_options() return arguments.parse_args()