From b384ca8fd28bfc41226718451f9dfcc58a0ce70b Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Jan 2020 20:30:03 +0100 Subject: [PATCH 01/27] Create new-config command --- freqtrade/commands/__init__.py | 1 + freqtrade/commands/arguments.py | 13 +++++++++++-- freqtrade/commands/deploy_commands.py | 8 ++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index 990c1107a..81467cf61 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -9,6 +9,7 @@ Note: Be careful with file-scoped imports in these subfiles. from freqtrade.commands.arguments import Arguments from freqtrade.commands.data_commands import start_download_data from freqtrade.commands.deploy_commands import (start_create_userdir, + start_new_config, start_new_hyperopt, start_new_strategy) from freqtrade.commands.hyperopt_commands import (start_hyperopt_list, diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 724814554..504c6b0b5 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -43,6 +43,8 @@ ARGS_TEST_PAIRLIST = ["config", "quote_currencies", "print_one_column", "list_pa ARGS_CREATE_USERDIR = ["user_data_dir", "reset"] +ARGS_BUILD_CONFIG = ["config"] + ARGS_BUILD_STRATEGY = ["user_data_dir", "strategy", "template"] ARGS_BUILD_HYPEROPT = ["user_data_dir", "hyperopt", "template"] @@ -133,8 +135,9 @@ class Arguments: from freqtrade.commands import (start_create_userdir, start_download_data, start_hyperopt_list, start_hyperopt_show, start_list_exchanges, start_list_markets, - start_list_strategies, start_new_hyperopt, - start_new_strategy, start_list_timeframes, + start_list_strategies, start_list_timeframes, + start_new_config, + start_new_hyperopt, start_new_strategy, start_plot_dataframe, start_plot_profit, start_backtesting, start_hyperopt, start_edge, start_test_pairlist, start_trading) @@ -177,6 +180,12 @@ class Arguments: create_userdir_cmd.set_defaults(func=start_create_userdir) self._build_args(optionlist=ARGS_CREATE_USERDIR, parser=create_userdir_cmd) + # add new-config subcommand + build_config_cmd = subparsers.add_parser('new-config', + help="Create new config") + build_config_cmd.set_defaults(func=start_new_config) + self._build_args(optionlist=ARGS_BUILD_CONFIG, parser=build_config_cmd) + # add new-strategy subcommand build_strategy_cmd = subparsers.add_parser('new-strategy', help="Create new strategy") diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 99ae63244..34755932c 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -110,3 +110,11 @@ def start_new_hyperopt(args: Dict[str, Any]) -> None: deploy_new_hyperopt(args['hyperopt'], new_path, args['template']) else: raise OperationalException("`new-hyperopt` requires --hyperopt to be set.") + + +def start_new_config(args: Dict[str, Any]) -> None: + """ + Create a new strategy from a template + Asking the user questions to fill out the templateaccordingly. + """ + pass From 9f291282056fde93c3cab74470764a9cdf80f89b Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 07:01:17 +0100 Subject: [PATCH 02/27] Fix small json formatting issue --- config.json.example | 2 +- config_binance.json.example | 2 +- config_full.json.example | 2 +- config_kraken.json.example | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config.json.example b/config.json.example index 8b85e71eb..a03ab6c2a 100644 --- a/config.json.example +++ b/config.json.example @@ -4,7 +4,7 @@ "stake_amount": 0.05, "tradable_balance_ratio": 0.99, "fiat_display_currency": "USD", - "ticker_interval" : "5m", + "ticker_interval": "5m", "dry_run": false, "trailing_stop": false, "unfilledtimeout": { diff --git a/config_binance.json.example b/config_binance.json.example index 0521a3a35..e2c9879b0 100644 --- a/config_binance.json.example +++ b/config_binance.json.example @@ -4,7 +4,7 @@ "stake_amount": 0.05, "tradable_balance_ratio": 0.99, "fiat_display_currency": "USD", - "ticker_interval" : "5m", + "ticker_interval": "5m", "dry_run": true, "trailing_stop": false, "unfilledtimeout": { diff --git a/config_full.json.example b/config_full.json.example index 82d8bd04a..f543604e7 100644 --- a/config_full.json.example +++ b/config_full.json.example @@ -4,7 +4,7 @@ "stake_amount": 0.05, "tradable_balance_ratio": 0.99, "fiat_display_currency": "USD", - "amount_reserve_percent" : 0.05, + "amount_reserve_percent": 0.05, "amend_last_stake_amount": false, "last_stake_amount_min_ratio": 0.5, "dry_run": false, diff --git a/config_kraken.json.example b/config_kraken.json.example index a527b569d..4f74d0b7d 100644 --- a/config_kraken.json.example +++ b/config_kraken.json.example @@ -4,7 +4,7 @@ "stake_amount": 10, "tradable_balance_ratio": 0.99, "fiat_display_currency": "EUR", - "ticker_interval" : "5m", + "ticker_interval": "5m", "dry_run": true, "trailing_stop": false, "unfilledtimeout": { From 122c9163566acfbbf2d2a18e86dfcfac3a772dab Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 07:01:32 +0100 Subject: [PATCH 03/27] Add first version of config_deploy --- freqtrade/commands/deploy_commands.py | 28 ++++++++- freqtrade/templates/base_config.json.j2 | 82 +++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 freqtrade/templates/base_config.json.j2 diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 34755932c..4e114a6d8 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -112,9 +112,35 @@ def start_new_hyperopt(args: Dict[str, Any]) -> None: raise OperationalException("`new-hyperopt` requires --hyperopt to be set.") +def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None: + """ + Applies selections to the template and writes the result to config_path + :param config_path: Path object for new config file. Should not exist yet + :param selecions: Dict containing selections taken by the user. + """ + config_text = render_template(templatefile='base_config.json.j2', + arguments=selections) + + config_path.write_text(config_text) + + def start_new_config(args: Dict[str, Any]) -> None: """ Create a new strategy from a template Asking the user questions to fill out the templateaccordingly. """ - pass + sample_selections = { + 'stake_currency': 'USDT', + 'stake_amount': 100, + 'fiat_display_currency': 'EUR', + 'ticker_interval': '15m', + 'dry_run': True, + 'exchange': 'binance', + 'exchange_key': 'sampleKey', + 'exchange_secret': 'Samplesecret', + 'telegram': True, + 'telegram_token': 'asdf1244', + 'telegram_chat_id': '1144444', + } + config_path = Path(args['config'][0]) + deploy_new_config(config_path, sample_selections) diff --git a/freqtrade/templates/base_config.json.j2 b/freqtrade/templates/base_config.json.j2 new file mode 100644 index 000000000..ad8a762ec --- /dev/null +++ b/freqtrade/templates/base_config.json.j2 @@ -0,0 +1,82 @@ +{ + "max_open_trades": 3, + "stake_currency": "{{ stake_currency }}", + "stake_amount": {{ stake_amount }}, + "tradable_balance_ratio": 0.99, + "fiat_display_currency": "{{ fiat_display_currency }}", + "ticker_interval": "{{ ticker_interval }}", + "dry_run": {{ dry_run | lower }}, + "unfilledtimeout": { + "buy": 10, + "sell": 30 + }, + "bid_strategy": { + "ask_last_balance": 0.0, + "use_order_book": false, + "order_book_top": 1, + "check_depth_of_market": { + "enabled": false, + "bids_to_ask_delta": 1 + } + }, + "ask_strategy":{ + "use_order_book": false, + "order_book_min": 1, + "order_book_max": 9, + "use_sell_signal": true, + "sell_profit_only": false, + "ignore_roi_if_buy_signal": false + }, + "exchange": { + "name": "bittrex", + "key": "your_exchange_key", + "secret": "your_exchange_secret", + "ccxt_config": {"enableRateLimit": true}, + "ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 500 + }, + "pair_whitelist": [ + "ETH/BTC", + "LTC/BTC", + "ETC/BTC", + "DASH/BTC", + "ZEC/BTC", + "XLM/BTC", + "NXT/BTC", + "TRX/BTC", + "ADA/BTC", + "XMR/BTC" + ], + "pair_blacklist": [ + "DOGE/BTC" + ] + }, + "pairlists": [ + {"method": "StaticPairList"} + ], + "edge": { + "enabled": false, + "process_throttle_secs": 3600, + "calculate_since_number_of_days": 7, + "allowed_risk": 0.01, + "stoploss_range_min": -0.01, + "stoploss_range_max": -0.1, + "stoploss_range_step": -0.01, + "minimum_winrate": 0.60, + "minimum_expectancy": 0.20, + "min_trade_number": 10, + "max_trade_duration_minute": 1440, + "remove_pumps": false + }, + "telegram": { + "enabled": {{ telegram | lower }}, + "token": "{{ telegram_token }}", + "chat_id": "{{ telegram_chat_id }}" + }, + "initial_state": "running", + "forcebuy_enable": false, + "internals": { + "process_throttle_secs": 5 + } +} From c80d8f432acc07665353947acae84a4d09cd3ced Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 07:13:38 +0100 Subject: [PATCH 04/27] Add exchange templates --- freqtrade/commands/deploy_commands.py | 19 +++++++++-- freqtrade/misc.py | 1 - freqtrade/templates/base_config.json.j2 | 24 +------------- .../subtemplates/exchange_binance.j2 | 28 ++++++++++++++++ .../subtemplates/exchange_generic.j2 | 13 ++++++++ .../templates/subtemplates/exchange_kraken.j2 | 33 +++++++++++++++++++ 6 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 freqtrade/templates/subtemplates/exchange_binance.j2 create mode 100644 freqtrade/templates/subtemplates/exchange_generic.j2 create mode 100644 freqtrade/templates/subtemplates/exchange_kraken.j2 diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 4e114a6d8..065703faa 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -118,9 +118,22 @@ def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None: :param config_path: Path object for new config file. Should not exist yet :param selecions: Dict containing selections taken by the user. """ + from jinja2.exceptions import TemplateNotFound + try: + selections['exchange'] = render_template( + templatefile=f"subtemplates/exchange_{selections['exchange_name']}.j2", + arguments=selections + ) + except TemplateNotFound: + selections['exchange'] = render_template( + templatefile=f"subtemplates/exchange_generic.j2", + arguments=selections + ) + config_text = render_template(templatefile='base_config.json.j2', arguments=selections) + logger.info(f"Writing config to `{config_path}`.") config_path.write_text(config_text) @@ -135,12 +148,14 @@ def start_new_config(args: Dict[str, Any]) -> None: 'fiat_display_currency': 'EUR', 'ticker_interval': '15m', 'dry_run': True, - 'exchange': 'binance', + 'exchange_name': 'binance', 'exchange_key': 'sampleKey', 'exchange_secret': 'Samplesecret', - 'telegram': True, + 'telegram': False, 'telegram_token': 'asdf1244', 'telegram_chat_id': '1144444', } config_path = Path(args['config'][0]) deploy_new_config(config_path, sample_selections) + + diff --git a/freqtrade/misc.py b/freqtrade/misc.py index bcba78cf0..40e1fdf17 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -138,5 +138,4 @@ def render_template(templatefile: str, arguments: dict = {}): autoescape=select_autoescape(['html', 'xml']) ) template = env.get_template(templatefile) - return template.render(**arguments) diff --git a/freqtrade/templates/base_config.json.j2 b/freqtrade/templates/base_config.json.j2 index ad8a762ec..f2f919e1f 100644 --- a/freqtrade/templates/base_config.json.j2 +++ b/freqtrade/templates/base_config.json.j2 @@ -28,29 +28,7 @@ "ignore_roi_if_buy_signal": false }, "exchange": { - "name": "bittrex", - "key": "your_exchange_key", - "secret": "your_exchange_secret", - "ccxt_config": {"enableRateLimit": true}, - "ccxt_async_config": { - "enableRateLimit": true, - "rateLimit": 500 - }, - "pair_whitelist": [ - "ETH/BTC", - "LTC/BTC", - "ETC/BTC", - "DASH/BTC", - "ZEC/BTC", - "XLM/BTC", - "NXT/BTC", - "TRX/BTC", - "ADA/BTC", - "XMR/BTC" - ], - "pair_blacklist": [ - "DOGE/BTC" - ] + {{ exchange | indent(8) }} }, "pairlists": [ {"method": "StaticPairList"} diff --git a/freqtrade/templates/subtemplates/exchange_binance.j2 b/freqtrade/templates/subtemplates/exchange_binance.j2 new file mode 100644 index 000000000..082af45c4 --- /dev/null +++ b/freqtrade/templates/subtemplates/exchange_binance.j2 @@ -0,0 +1,28 @@ +"name": "{{ exchange_name | lower }}", +"key": "{{ exchange_key }}", +"secret": "{{ exchange_secret }}", +"ccxt_config": {"enableRateLimit": true}, +"ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 200 +}, +"pair_whitelist": [ + "ALGO/BTC", + "ATOM/BTC", + "BAT/BTC", + "BCH/BTC", + "BRD/BTC", + "EOS/BTC", + "ETH/BTC", + "IOTA/BTC", + "LINK/BTC", + "LTC/BTC", + "NEO/BTC", + "NXS/BTC", + "XMR/BTC", + "XRP/BTC", + "XTZ/BTC" +], +"pair_blacklist": [ + "BNB/BTC" +] diff --git a/freqtrade/templates/subtemplates/exchange_generic.j2 b/freqtrade/templates/subtemplates/exchange_generic.j2 new file mode 100644 index 000000000..5d5bee2b2 --- /dev/null +++ b/freqtrade/templates/subtemplates/exchange_generic.j2 @@ -0,0 +1,13 @@ +"name": "{{ exchange_name | lower }}", +"key": "{{ exchange_key }}", +"secret": "{{ exchange_secret }}", +"ccxt_config": {"enableRateLimit": true}, +"ccxt_async_config": { + "enableRateLimit": true, +}, +"pair_whitelist": [ + +], +"pair_blacklist": [ + +] diff --git a/freqtrade/templates/subtemplates/exchange_kraken.j2 b/freqtrade/templates/subtemplates/exchange_kraken.j2 new file mode 100644 index 000000000..690828887 --- /dev/null +++ b/freqtrade/templates/subtemplates/exchange_kraken.j2 @@ -0,0 +1,33 @@ +"name": "kraken", +"key": "{{ exchange_key }}", +"secret": "{{ exchange_secret }}", +"ccxt_config": {"enableRateLimit": true}, +"ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 1000 +}, +"pair_whitelist": [ + "ADA/EUR", + "ATOM/EUR", + "BAT/EUR", + "BCH/EUR", + "BTC/EUR", + "DAI/EUR", + "DASH/EUR", + "EOS/EUR", + "ETC/EUR", + "ETH/EUR", + "LINK/EUR", + "LTC/EUR", + "QTUM/EUR", + "REP/EUR", + "WAVES/EUR", + "XLM/EUR", + "XMR/EUR", + "XRP/EUR", + "XTZ/EUR", + "ZEC/EUR" +], +"pair_blacklist": [ + +] From dd83cb1b95fb2a0f3790d7c83a377ed72b659fd3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 20:27:38 +0100 Subject: [PATCH 05/27] Extract selection generation to a seperate method --- freqtrade/commands/deploy_commands.py | 38 ++++++++++++++++--------- freqtrade/templates/base_config.json.j2 | 2 +- tests/commands/test_commands.py | 21 ++++++++++++-- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 065703faa..87aea7492 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -112,6 +112,28 @@ def start_new_hyperopt(args: Dict[str, Any]) -> None: raise OperationalException("`new-hyperopt` requires --hyperopt to be set.") +def ask_user_config() -> Dict[str, Any]: + """ + Ask user a few questions to build the configuration. + :returns: Dict with keys to put into template + """ + sample_selections = { + 'max_open_trades': 3, + 'stake_currency': 'USDT', + 'stake_amount': 100, + 'fiat_display_currency': 'EUR', + 'ticker_interval': '15m', + 'dry_run': True, + 'exchange_name': 'binance', + 'exchange_key': 'sampleKey', + 'exchange_secret': 'Samplesecret', + 'telegram': False, + 'telegram_token': 'asdf1244', + 'telegram_chat_id': '1144444', + } + return sample_selections + + def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None: """ Applies selections to the template and writes the result to config_path @@ -142,20 +164,8 @@ def start_new_config(args: Dict[str, Any]) -> None: Create a new strategy from a template Asking the user questions to fill out the templateaccordingly. """ - sample_selections = { - 'stake_currency': 'USDT', - 'stake_amount': 100, - 'fiat_display_currency': 'EUR', - 'ticker_interval': '15m', - 'dry_run': True, - 'exchange_name': 'binance', - 'exchange_key': 'sampleKey', - 'exchange_secret': 'Samplesecret', - 'telegram': False, - 'telegram_token': 'asdf1244', - 'telegram_chat_id': '1144444', - } + selections = ask_user_config() config_path = Path(args['config'][0]) - deploy_new_config(config_path, sample_selections) + deploy_new_config(config_path, selections) diff --git a/freqtrade/templates/base_config.json.j2 b/freqtrade/templates/base_config.json.j2 index f2f919e1f..1370bfa80 100644 --- a/freqtrade/templates/base_config.json.j2 +++ b/freqtrade/templates/base_config.json.j2 @@ -1,5 +1,5 @@ { - "max_open_trades": 3, + "max_open_trades": {{ max_open_trades }}, "stake_currency": "{{ stake_currency }}", "stake_amount": {{ stake_amount }}, "tradable_balance_ratio": 0.99, diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 65d7f6eaf..f8efdfd3c 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -8,8 +8,9 @@ from freqtrade.commands import (start_create_userdir, start_download_data, start_hyperopt_list, start_hyperopt_show, start_list_exchanges, start_list_markets, start_list_strategies, start_list_timeframes, - start_new_hyperopt, start_new_strategy, - start_test_pairlist, start_trading) + start_new_config, start_new_hyperopt, + start_new_strategy, start_test_pairlist, + start_trading) from freqtrade.configuration import setup_utils_configuration from freqtrade.exceptions import OperationalException from freqtrade.state import RunMode @@ -537,6 +538,22 @@ def test_start_new_hyperopt_no_arg(mocker, caplog): start_new_hyperopt(get_args(args)) +def test_start_new_config(mocker, caplog): + wt_mock = mocker.patch.object(Path, "write_text", MagicMock()) + mocker.patch.object(Path, "exists", MagicMock(return_value=False)) + + args = [ + "new-config", + "--config", + "coolconfig.json" + ] + start_new_config(get_args(args)) + + assert wt_mock.call_count == 1 + assert "binance" in wt_mock.call_args_list[0][0][0] + assert log_has_re("Writing config to .*", caplog) + + def test_download_data_keyboardInterrupt(mocker, caplog, markets): dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data', MagicMock(side_effect=KeyboardInterrupt)) From 49c9258a088e42db46656b24fc90d1227d604dc1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 20:32:27 +0100 Subject: [PATCH 06/27] enhance test --- tests/commands/test_commands.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index f8efdfd3c..19999f319 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1,3 +1,4 @@ +import json import re from pathlib import Path from unittest.mock import MagicMock, PropertyMock @@ -538,10 +539,26 @@ def test_start_new_hyperopt_no_arg(mocker, caplog): start_new_hyperopt(get_args(args)) -def test_start_new_config(mocker, caplog): +@pytest.mark.parametrize('exchange', ['bittrex', 'binance', 'kraken', 'ftx']) +def test_start_new_config(mocker, caplog, exchange): wt_mock = mocker.patch.object(Path, "write_text", MagicMock()) mocker.patch.object(Path, "exists", MagicMock(return_value=False)) - + sample_selections = { + 'max_open_trades': 3, + 'stake_currency': 'USDT', + 'stake_amount': 100, + 'fiat_display_currency': 'EUR', + 'ticker_interval': '15m', + 'dry_run': True, + 'exchange_name': exchange, + 'exchange_key': 'sampleKey', + 'exchange_secret': 'Samplesecret', + 'telegram': False, + 'telegram_token': 'asdf1244', + 'telegram_chat_id': '1144444', + } + mocker.patch('freqtrade.commands.deploy_commands.ask_user_config', + return_value=sample_selections) args = [ "new-config", "--config", @@ -549,9 +566,11 @@ def test_start_new_config(mocker, caplog): ] start_new_config(get_args(args)) - assert wt_mock.call_count == 1 - assert "binance" in wt_mock.call_args_list[0][0][0] assert log_has_re("Writing config to .*", caplog) + assert wt_mock.call_count == 1 + result = json.loads(wt_mock.call_args_list[0][0][0]) + assert result['exchange']['name'] == exchange + assert result['ticker_interval'] == '15m' def test_download_data_keyboardInterrupt(mocker, caplog, markets): From e250c56829e74445e6177d4b61c17e57a0af21e0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 21:21:38 +0100 Subject: [PATCH 07/27] Add Questionaire workflow --- freqtrade/commands/deploy_commands.py | 98 ++++++++++++++++++++++++++- requirements-common.txt | 3 + setup.py | 2 + 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 87aea7492..670f272ce 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -3,11 +3,14 @@ import sys from pathlib import Path from typing import Any, Dict +from questionary import Separator, prompt + from freqtrade.configuration import setup_utils_configuration from freqtrade.configuration.directory_operations import (copy_sample_files, create_userdata_dir) from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGY from freqtrade.exceptions import OperationalException +from freqtrade.exchange import available_exchanges from freqtrade.misc import render_template from freqtrade.state import RunMode @@ -117,6 +120,99 @@ def ask_user_config() -> Dict[str, Any]: Ask user a few questions to build the configuration. :returns: Dict with keys to put into template """ + questions = [ + { + "type": "confirm", + "name": "dry_run", + "message": "Do you want to enable Dry-run (simulated trades)?", + "default": True, + }, + { + "type": "text", + "name": "stake_currency", + "message": "Please insert your stake currency:", + "default": 'BTC', + }, + { + "type": "text", + "name": "stake_amount", + "message": "Please insert your stake amount:", + "default": "0.01", + }, + { + "type": "text", + "name": "max_open_trades", + "message": "Please insert max_open_trades:", + "default": "3", + }, + { + "type": "text", + "name": "ticker_interval", + "message": "Please insert your ticker interval:", + "default": "5m", + }, + { + "type": "text", + "name": "fiat_display_currency", + "message": "Please insert your display Currency (for reporting):", + "default": 'USD', + }, + { + "type": "select", + "name": "exchange_name", + "message": "Select exchange", + "choices": [ + "bittrex", + "binance", + "binanceje", + "binanceus", + "kraken", + Separator(), + "other", + ], + }, + { + "type": "autocomplete", + "name": "exchange_name", + "message": "Type your exchange name (Must be supported by ccxt)", + "choices": available_exchanges(), + "when": lambda x: x["exchange_name"] == 'other' + }, + { + "type": "password", + "name": "exchange_key", + "message": "Insert Exchange Key", + "when": lambda x: not x['dry_run'] + }, + { + "type": "password", + "name": "exchange_secret", + "message": "Insert Exchange Secret", + "when": lambda x: not x['dry_run'] + }, + { + "type": "confirm", + "name": "telegram", + "message": "Do you want to enable Telegram?", + "default": False, + }, + { + "type": "password", + "name": "telegram_token", + "message": "Insert Telegram token", + "when": lambda x: x['telegram'] + }, + { + "type": "text", + "name": "telegram_chat_id", + "message": "Insert Telegram chat id", + "when": lambda x: x['telegram'] + }, + ] + answers = prompt(questions) + + print(answers) + sample_selections = { 'max_open_trades': 3, 'stake_currency': 'USDT', @@ -167,5 +263,3 @@ def start_new_config(args: Dict[str, Any]) -> None: selections = ask_user_config() config_path = Path(args['config'][0]) deploy_new_config(config_path, selections) - - diff --git a/requirements-common.txt b/requirements-common.txt index e4fe54721..80f18892b 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -28,3 +28,6 @@ flask==1.1.1 # Support for colorized terminal output colorama==0.4.3 +# Building config files interactively +questionary==1.5.1 +prompt-toolkit==3.0.3 diff --git a/setup.py b/setup.py index 7d8d7b68d..63a595f32 100644 --- a/setup.py +++ b/setup.py @@ -79,6 +79,8 @@ setup(name='freqtrade', 'sdnotify', 'colorama', 'jinja2', + 'questionary', + 'prompt-toolkit', # from requirements.txt 'numpy', 'pandas', From 940bfbee96eef00e56d7f5097f1c59099b34bb37 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 21:28:01 +0100 Subject: [PATCH 08/27] Move start_config out of build_commands file --- freqtrade/commands/__init__.py | 2 +- freqtrade/commands/build_config_commands.py | 160 ++++++++++++++++++ freqtrade/commands/deploy_commands.py | 153 ----------------- .../subtemplates/exchange_generic.j2 | 2 +- tests/commands/test_commands.py | 2 +- 5 files changed, 163 insertions(+), 156 deletions(-) create mode 100644 freqtrade/commands/build_config_commands.py diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index 81467cf61..6ea325e63 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -7,9 +7,9 @@ Note: Be careful with file-scoped imports in these subfiles. as they are parsed on startup, nothing containing optional modules should be loaded. """ from freqtrade.commands.arguments import Arguments +from freqtrade.commands.build_config_commands import start_new_config from freqtrade.commands.data_commands import start_download_data from freqtrade.commands.deploy_commands import (start_create_userdir, - start_new_config, start_new_hyperopt, start_new_strategy) from freqtrade.commands.hyperopt_commands import (start_hyperopt_list, diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py new file mode 100644 index 000000000..393416f53 --- /dev/null +++ b/freqtrade/commands/build_config_commands.py @@ -0,0 +1,160 @@ +import logging +from pathlib import Path +from typing import Any, Dict + +from questionary import Separator, prompt + +from freqtrade.exchange import available_exchanges +from freqtrade.misc import render_template + +logger = logging.getLogger(__name__) + + +def ask_user_config() -> Dict[str, Any]: + """ + Ask user a few questions to build the configuration. + :returns: Dict with keys to put into template + """ + questions = [ + { + "type": "confirm", + "name": "dry_run", + "message": "Do you want to enable Dry-run (simulated trades)?", + "default": True, + }, + { + "type": "text", + "name": "stake_currency", + "message": "Please insert your stake currency:", + "default": 'BTC', + }, + { + "type": "text", + "name": "stake_amount", + "message": "Please insert your stake amount:", + "default": "0.01", + }, + { + "type": "text", + "name": "max_open_trades", + "message": "Please insert max_open_trades:", + "default": "3", + }, + { + "type": "text", + "name": "ticker_interval", + "message": "Please insert your ticker interval:", + "default": "5m", + }, + { + "type": "text", + "name": "fiat_display_currency", + "message": "Please insert your display Currency (for reporting):", + "default": 'USD', + }, + { + "type": "select", + "name": "exchange_name", + "message": "Select exchange", + "choices": [ + "bittrex", + "binance", + "binanceje", + "binanceus", + "kraken", + Separator(), + "other", + ], + }, + { + "type": "autocomplete", + "name": "exchange_name", + "message": "Type your exchange name (Must be supported by ccxt)", + "choices": available_exchanges(), + "when": lambda x: x["exchange_name"] == 'other' + }, + { + "type": "password", + "name": "exchange_key", + "message": "Insert Exchange Key", + "when": lambda x: not x['dry_run'] + }, + { + "type": "password", + "name": "exchange_secret", + "message": "Insert Exchange Secret", + "when": lambda x: not x['dry_run'] + }, + { + "type": "confirm", + "name": "telegram", + "message": "Do you want to enable Telegram?", + "default": False, + }, + { + "type": "password", + "name": "telegram_token", + "message": "Insert Telegram token", + "when": lambda x: x['telegram'] + }, + { + "type": "text", + "name": "telegram_chat_id", + "message": "Insert Telegram chat id", + "when": lambda x: x['telegram'] + }, + ] + answers = prompt(questions) + + print(answers) + + sample_selections = { + 'max_open_trades': 3, + 'stake_currency': 'USDT', + 'stake_amount': 100, + 'fiat_display_currency': 'EUR', + 'ticker_interval': '15m', + 'dry_run': True, + 'exchange_name': 'binance', + 'exchange_key': 'sampleKey', + 'exchange_secret': 'Samplesecret', + 'telegram': False, + 'telegram_token': 'asdf1244', + 'telegram_chat_id': '1144444', + } + return sample_selections + + +def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None: + """ + Applies selections to the template and writes the result to config_path + :param config_path: Path object for new config file. Should not exist yet + :param selecions: Dict containing selections taken by the user. + """ + from jinja2.exceptions import TemplateNotFound + try: + selections['exchange'] = render_template( + templatefile=f"subtemplates/exchange_{selections['exchange_name']}.j2", + arguments=selections + ) + except TemplateNotFound: + selections['exchange'] = render_template( + templatefile=f"subtemplates/exchange_generic.j2", + arguments=selections + ) + + config_text = render_template(templatefile='base_config.json.j2', + arguments=selections) + + logger.info(f"Writing config to `{config_path}`.") + config_path.write_text(config_text) + + +def start_new_config(args: Dict[str, Any]) -> None: + """ + Create a new strategy from a template + Asking the user questions to fill out the templateaccordingly. + """ + selections = ask_user_config() + config_path = Path(args['config'][0]) + deploy_new_config(config_path, selections) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 670f272ce..99ae63244 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -3,14 +3,11 @@ import sys from pathlib import Path from typing import Any, Dict -from questionary import Separator, prompt - from freqtrade.configuration import setup_utils_configuration from freqtrade.configuration.directory_operations import (copy_sample_files, create_userdata_dir) from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGY from freqtrade.exceptions import OperationalException -from freqtrade.exchange import available_exchanges from freqtrade.misc import render_template from freqtrade.state import RunMode @@ -113,153 +110,3 @@ def start_new_hyperopt(args: Dict[str, Any]) -> None: deploy_new_hyperopt(args['hyperopt'], new_path, args['template']) else: raise OperationalException("`new-hyperopt` requires --hyperopt to be set.") - - -def ask_user_config() -> Dict[str, Any]: - """ - Ask user a few questions to build the configuration. - :returns: Dict with keys to put into template - """ - questions = [ - { - "type": "confirm", - "name": "dry_run", - "message": "Do you want to enable Dry-run (simulated trades)?", - "default": True, - }, - { - "type": "text", - "name": "stake_currency", - "message": "Please insert your stake currency:", - "default": 'BTC', - }, - { - "type": "text", - "name": "stake_amount", - "message": "Please insert your stake amount:", - "default": "0.01", - }, - { - "type": "text", - "name": "max_open_trades", - "message": "Please insert max_open_trades:", - "default": "3", - }, - { - "type": "text", - "name": "ticker_interval", - "message": "Please insert your ticker interval:", - "default": "5m", - }, - { - "type": "text", - "name": "fiat_display_currency", - "message": "Please insert your display Currency (for reporting):", - "default": 'USD', - }, - { - "type": "select", - "name": "exchange_name", - "message": "Select exchange", - "choices": [ - "bittrex", - "binance", - "binanceje", - "binanceus", - "kraken", - Separator(), - "other", - ], - }, - { - "type": "autocomplete", - "name": "exchange_name", - "message": "Type your exchange name (Must be supported by ccxt)", - "choices": available_exchanges(), - "when": lambda x: x["exchange_name"] == 'other' - }, - { - "type": "password", - "name": "exchange_key", - "message": "Insert Exchange Key", - "when": lambda x: not x['dry_run'] - }, - { - "type": "password", - "name": "exchange_secret", - "message": "Insert Exchange Secret", - "when": lambda x: not x['dry_run'] - }, - { - "type": "confirm", - "name": "telegram", - "message": "Do you want to enable Telegram?", - "default": False, - }, - { - "type": "password", - "name": "telegram_token", - "message": "Insert Telegram token", - "when": lambda x: x['telegram'] - }, - { - "type": "text", - "name": "telegram_chat_id", - "message": "Insert Telegram chat id", - "when": lambda x: x['telegram'] - }, - ] - answers = prompt(questions) - - print(answers) - - sample_selections = { - 'max_open_trades': 3, - 'stake_currency': 'USDT', - 'stake_amount': 100, - 'fiat_display_currency': 'EUR', - 'ticker_interval': '15m', - 'dry_run': True, - 'exchange_name': 'binance', - 'exchange_key': 'sampleKey', - 'exchange_secret': 'Samplesecret', - 'telegram': False, - 'telegram_token': 'asdf1244', - 'telegram_chat_id': '1144444', - } - return sample_selections - - -def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None: - """ - Applies selections to the template and writes the result to config_path - :param config_path: Path object for new config file. Should not exist yet - :param selecions: Dict containing selections taken by the user. - """ - from jinja2.exceptions import TemplateNotFound - try: - selections['exchange'] = render_template( - templatefile=f"subtemplates/exchange_{selections['exchange_name']}.j2", - arguments=selections - ) - except TemplateNotFound: - selections['exchange'] = render_template( - templatefile=f"subtemplates/exchange_generic.j2", - arguments=selections - ) - - config_text = render_template(templatefile='base_config.json.j2', - arguments=selections) - - logger.info(f"Writing config to `{config_path}`.") - config_path.write_text(config_text) - - -def start_new_config(args: Dict[str, Any]) -> None: - """ - Create a new strategy from a template - Asking the user questions to fill out the templateaccordingly. - """ - selections = ask_user_config() - config_path = Path(args['config'][0]) - deploy_new_config(config_path, selections) diff --git a/freqtrade/templates/subtemplates/exchange_generic.j2 b/freqtrade/templates/subtemplates/exchange_generic.j2 index 5d5bee2b2..33309de3b 100644 --- a/freqtrade/templates/subtemplates/exchange_generic.j2 +++ b/freqtrade/templates/subtemplates/exchange_generic.j2 @@ -3,7 +3,7 @@ "secret": "{{ exchange_secret }}", "ccxt_config": {"enableRateLimit": true}, "ccxt_async_config": { - "enableRateLimit": true, + "enableRateLimit": true }, "pair_whitelist": [ diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 19999f319..51b69449d 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -557,7 +557,7 @@ def test_start_new_config(mocker, caplog, exchange): 'telegram_token': 'asdf1244', 'telegram_chat_id': '1144444', } - mocker.patch('freqtrade.commands.deploy_commands.ask_user_config', + mocker.patch('freqtrade.commands.build_config_commands.ask_user_config', return_value=sample_selections) args = [ "new-config", From 2f0775fa1b6381b163ecd55ba1a0b684a9bbfea8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 21:30:29 +0100 Subject: [PATCH 09/27] Extract build-config tests to new file --- tests/commands/test_build_config.py | 42 +++++++++++++++++++++++++++++ tests/commands/test_commands.py | 40 ++------------------------- 2 files changed, 44 insertions(+), 38 deletions(-) create mode 100644 tests/commands/test_build_config.py diff --git a/tests/commands/test_build_config.py b/tests/commands/test_build_config.py new file mode 100644 index 000000000..4114ff489 --- /dev/null +++ b/tests/commands/test_build_config.py @@ -0,0 +1,42 @@ +import json +from pathlib import Path +from unittest.mock import MagicMock + +import pytest + +from freqtrade.commands import start_new_config +from tests.conftest import get_args, log_has_re + + +@pytest.mark.parametrize('exchange', ['bittrex', 'binance', 'kraken', 'ftx']) +def test_start_new_config(mocker, caplog, exchange): + wt_mock = mocker.patch.object(Path, "write_text", MagicMock()) + mocker.patch.object(Path, "exists", MagicMock(return_value=False)) + sample_selections = { + 'max_open_trades': 3, + 'stake_currency': 'USDT', + 'stake_amount': 100, + 'fiat_display_currency': 'EUR', + 'ticker_interval': '15m', + 'dry_run': True, + 'exchange_name': exchange, + 'exchange_key': 'sampleKey', + 'exchange_secret': 'Samplesecret', + 'telegram': False, + 'telegram_token': 'asdf1244', + 'telegram_chat_id': '1144444', + } + mocker.patch('freqtrade.commands.build_config_commands.ask_user_config', + return_value=sample_selections) + args = [ + "new-config", + "--config", + "coolconfig.json" + ] + start_new_config(get_args(args)) + + assert log_has_re("Writing config to .*", caplog) + assert wt_mock.call_count == 1 + result = json.loads(wt_mock.call_args_list[0][0][0]) + assert result['exchange']['name'] == exchange + assert result['ticker_interval'] == '15m' diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 51b69449d..65d7f6eaf 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1,4 +1,3 @@ -import json import re from pathlib import Path from unittest.mock import MagicMock, PropertyMock @@ -9,9 +8,8 @@ from freqtrade.commands import (start_create_userdir, start_download_data, start_hyperopt_list, start_hyperopt_show, start_list_exchanges, start_list_markets, start_list_strategies, start_list_timeframes, - start_new_config, start_new_hyperopt, - start_new_strategy, start_test_pairlist, - start_trading) + start_new_hyperopt, start_new_strategy, + start_test_pairlist, start_trading) from freqtrade.configuration import setup_utils_configuration from freqtrade.exceptions import OperationalException from freqtrade.state import RunMode @@ -539,40 +537,6 @@ def test_start_new_hyperopt_no_arg(mocker, caplog): start_new_hyperopt(get_args(args)) -@pytest.mark.parametrize('exchange', ['bittrex', 'binance', 'kraken', 'ftx']) -def test_start_new_config(mocker, caplog, exchange): - wt_mock = mocker.patch.object(Path, "write_text", MagicMock()) - mocker.patch.object(Path, "exists", MagicMock(return_value=False)) - sample_selections = { - 'max_open_trades': 3, - 'stake_currency': 'USDT', - 'stake_amount': 100, - 'fiat_display_currency': 'EUR', - 'ticker_interval': '15m', - 'dry_run': True, - 'exchange_name': exchange, - 'exchange_key': 'sampleKey', - 'exchange_secret': 'Samplesecret', - 'telegram': False, - 'telegram_token': 'asdf1244', - 'telegram_chat_id': '1144444', - } - mocker.patch('freqtrade.commands.build_config_commands.ask_user_config', - return_value=sample_selections) - args = [ - "new-config", - "--config", - "coolconfig.json" - ] - start_new_config(get_args(args)) - - assert log_has_re("Writing config to .*", caplog) - assert wt_mock.call_count == 1 - result = json.loads(wt_mock.call_args_list[0][0][0]) - assert result['exchange']['name'] == exchange - assert result['ticker_interval'] == '15m' - - def test_download_data_keyboardInterrupt(mocker, caplog, markets): dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data', MagicMock(side_effect=KeyboardInterrupt)) From acbf13e648425987d19654123d7e9d2ae83e8da7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 21:47:05 +0100 Subject: [PATCH 10/27] Fail gracefully if user interrupted question session --- freqtrade/commands/build_config_commands.py | 24 ++++++--------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 393416f53..a6623c3cd 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -6,13 +6,14 @@ from questionary import Separator, prompt from freqtrade.exchange import available_exchanges from freqtrade.misc import render_template - +from freqtrade.exceptions import OperationalException logger = logging.getLogger(__name__) def ask_user_config() -> Dict[str, Any]: """ Ask user a few questions to build the configuration. + Interactive questions built using https://github.com/tmbo/questionary :returns: Dict with keys to put into template """ questions = [ @@ -106,23 +107,11 @@ def ask_user_config() -> Dict[str, Any]: ] answers = prompt(questions) - print(answers) + if not answers: + # Interrupted questionary sessions return an empty dict. + raise OperationalException("User interrupted interactive questions.") - sample_selections = { - 'max_open_trades': 3, - 'stake_currency': 'USDT', - 'stake_amount': 100, - 'fiat_display_currency': 'EUR', - 'ticker_interval': '15m', - 'dry_run': True, - 'exchange_name': 'binance', - 'exchange_key': 'sampleKey', - 'exchange_secret': 'Samplesecret', - 'telegram': False, - 'telegram_token': 'asdf1244', - 'telegram_chat_id': '1144444', - } - return sample_selections + return answers def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None: @@ -156,5 +145,6 @@ def start_new_config(args: Dict[str, Any]) -> None: Asking the user questions to fill out the templateaccordingly. """ selections = ask_user_config() + config_path = Path(args['config'][0]) deploy_new_config(config_path, selections) From cebf99b5d890cd2979d5e68816b43d4c999bda7e Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 21:59:24 +0100 Subject: [PATCH 11/27] Implement validation --- freqtrade/commands/build_config_commands.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index a6623c3cd..6abacd826 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -4,12 +4,29 @@ from typing import Any, Dict from questionary import Separator, prompt +from freqtrade.constants import UNLIMITED_STAKE_AMOUNT from freqtrade.exchange import available_exchanges from freqtrade.misc import render_template from freqtrade.exceptions import OperationalException logger = logging.getLogger(__name__) +def validate_is_int(val): + try: + _ = int(val) + return True + except Exception: + return False + + +def validate_is_float(val): + try: + _ = float(val) + return True + except Exception: + return False + + def ask_user_config() -> Dict[str, Any]: """ Ask user a few questions to build the configuration. @@ -34,12 +51,14 @@ def ask_user_config() -> Dict[str, Any]: "name": "stake_amount", "message": "Please insert your stake amount:", "default": "0.01", + "validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val), }, { "type": "text", "name": "max_open_trades", - "message": "Please insert max_open_trades:", + "message": f"Please insert max_open_trades (Integer or '{UNLIMITED_STAKE_AMOUNT}'):", "default": "3", + "validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_int(val) }, { "type": "text", From 83baa6ee2e2c59a4b97ecf76d091cca2c7389154 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Jan 2020 22:47:15 +0100 Subject: [PATCH 12/27] Add test stub --- tests/commands/test_build_config.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/commands/test_build_config.py b/tests/commands/test_build_config.py index 4114ff489..46e79b357 100644 --- a/tests/commands/test_build_config.py +++ b/tests/commands/test_build_config.py @@ -4,7 +4,8 @@ from unittest.mock import MagicMock import pytest -from freqtrade.commands import start_new_config +from freqtrade.commands.build_config_commands import (ask_user_config, + start_new_config) from tests.conftest import get_args, log_has_re @@ -40,3 +41,9 @@ def test_start_new_config(mocker, caplog, exchange): result = json.loads(wt_mock.call_args_list[0][0][0]) assert result['exchange']['name'] == exchange assert result['ticker_interval'] == '15m' + + +def test_ask_user_config(): + # TODO: Implement me + pass + # assert ask_user_config() From 4be3f053ca38fc5534a445ac08ff0766708f17df Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 30 Jan 2020 21:42:48 +0100 Subject: [PATCH 13/27] Exclude trading against BNB bases on binance --- .../templates/subtemplates/exchange_binance.j2 | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/freqtrade/templates/subtemplates/exchange_binance.j2 b/freqtrade/templates/subtemplates/exchange_binance.j2 index 082af45c4..c527d296b 100644 --- a/freqtrade/templates/subtemplates/exchange_binance.j2 +++ b/freqtrade/templates/subtemplates/exchange_binance.j2 @@ -24,5 +24,16 @@ "XTZ/BTC" ], "pair_blacklist": [ - "BNB/BTC" + "BNB/BTC", + "BNB/BUSD", + "BNB/ETH", + "BNB/EUR", + "BNB/NGN", + "BNB/PAX", + "BNB/RUB", + "BNB/TRY", + "BNB/TUSD", + "BNB/USDC", + "BNB/USDS", + "BNB/USDT", ] From d69ef4380b273468b20c652fb5e6f3d489fc4dd6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 13:44:04 +0100 Subject: [PATCH 14/27] Add basic documentation for new-config option --- docs/utils.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/utils.md b/docs/utils.md index 18deeac54..df2a1c3c3 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -36,6 +36,24 @@ optional arguments: └── sample_strategy.py ``` +## Create new config + +Creates a new configuration file, asking some questions which are important selections for a configuration. + + +``` +usage: freqtrade new-config [-h] [-c PATH] + +optional arguments: + -h, --help show this help message and exit + -c PATH, --config PATH + Specify configuration file (default: `config.json`). Multiple --config options may be used. Can be set to `-` + to read config from stdin. +``` + +!!! Warning + Only vital questions are asked. Freqtrade offers a lot more configuration possibilities, which are listed in the [Configuration documentation](configuration.md#configuration-parameters) + ## Create new strategy Creates a new strategy from a template similar to SampleStrategy. From c40a4d77f8972c80be8be311a9dfd183a1222a64 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 13:46:58 +0100 Subject: [PATCH 15/27] Use exchange_mapping to determine correct exchange-template --- freqtrade/commands/build_config_commands.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 6abacd826..e0910e5b7 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -5,7 +5,7 @@ from typing import Any, Dict from questionary import Separator, prompt from freqtrade.constants import UNLIMITED_STAKE_AMOUNT -from freqtrade.exchange import available_exchanges +from freqtrade.exchange import available_exchanges, MAP_EXCHANGE_CHILDCLASS from freqtrade.misc import render_template from freqtrade.exceptions import OperationalException logger = logging.getLogger(__name__) @@ -141,8 +141,11 @@ def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None: """ from jinja2.exceptions import TemplateNotFound try: + exchange_template = MAP_EXCHANGE_CHILDCLASS.get( + selections['exchange_name'], selections['exchange_name']) + selections['exchange'] = render_template( - templatefile=f"subtemplates/exchange_{selections['exchange_name']}.j2", + templatefile=f"subtemplates/exchange_{exchange_template}.j2", arguments=selections ) except TemplateNotFound: From 54512a66ef187aedcddc048968f822b515fa510d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 13:52:25 +0100 Subject: [PATCH 16/27] Update help-strings for list-utils --- docs/utils.md | 51 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/docs/utils.md b/docs/utils.md index df2a1c3c3..44cbc35d6 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -197,20 +197,31 @@ All exchanges supported by the ccxt library: _1btcxe, acx, adara, allcoin, anxpr Use the `list-timeframes` subcommand to see the list of ticker intervals (timeframes) available for the exchange. ``` -usage: freqtrade list-timeframes [-h] [--exchange EXCHANGE] [-1] +usage: freqtrade list-timeframes [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [--exchange EXCHANGE] [-1] optional arguments: - -h, --help show this help message and exit - --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no - config is provided. - -1, --one-column Print output in one column. + -h, --help show this help message and exit + --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no config is provided. + -1, --one-column Print output in one column. + +Common arguments: + -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). + --logfile FILE Log to the file specified. Special values are: 'syslog', 'journald'. See the documentation for more details. + -V, --version show program's version number and exit + -c PATH, --config PATH + Specify configuration file (default: `config.json`). Multiple --config options may be used. Can be set to `-` + to read config from stdin. + -d PATH, --datadir PATH + Path to directory with historical backtesting data. + --userdir PATH, --user-data-dir PATH + Path to userdata directory. ``` * Example: see the timeframes for the 'binance' exchange, set in the configuration file: ``` -$ freqtrade -c config_binance.json list-timeframes +$ freqtrade list-timeframes -c config_binance.json ... Timeframes available for the exchange `binance`: 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M ``` @@ -234,14 +245,16 @@ You can print info about any pair/market with these subcommands - and you can fi These subcommands have same usage and same set of available options: ``` -usage: freqtrade list-markets [-h] [--exchange EXCHANGE] [--print-list] - [--print-json] [-1] [--print-csv] +usage: freqtrade list-markets [-h] [-v] [--logfile FILE] [-V] [-c PATH] + [-d PATH] [--userdir PATH] [--exchange EXCHANGE] + [--print-list] [--print-json] [-1] [--print-csv] [--base BASE_CURRENCY [BASE_CURRENCY ...]] [--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]] [-a] -usage: freqtrade list-pairs [-h] [--exchange EXCHANGE] [--print-list] - [--print-json] [-1] [--print-csv] +usage: freqtrade list-pairs [-h] [-v] [--logfile FILE] [-V] [-c PATH] + [-d PATH] [--userdir PATH] [--exchange EXCHANGE] + [--print-list] [--print-json] [-1] [--print-csv] [--base BASE_CURRENCY [BASE_CURRENCY ...]] [--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]] [-a] @@ -260,6 +273,22 @@ optional arguments: Specify quote currency(-ies). Space-separated list. -a, --all Print all pairs or market symbols. By default only active ones are shown. + +Common arguments: + -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). + --logfile FILE Log to the file specified. Special values are: + 'syslog', 'journald'. See the documentation for more + details. + -V, --version show program's version number and exit + -c PATH, --config PATH + Specify configuration file (default: `config.json`). + Multiple --config options may be used. Can be set to + `-` to read config from stdin. + -d PATH, --datadir PATH + Path to directory with historical backtesting data. + --userdir PATH, --user-data-dir PATH + Path to userdata directory. + ``` By default, only active pairs/markets are shown. Active pairs/markets are those that can currently be traded @@ -281,7 +310,7 @@ $ freqtrade list-pairs --quote USD --print-json human-readable list with summary: ``` -$ freqtrade -c config_binance.json list-pairs --all --base BTC ETH --quote USDT USD --print-list +$ freqtrade list-pairs -c config_binance.json --all --base BTC ETH --quote USDT USD --print-list ``` * Print all markets on exchange "Kraken", in the tabular format: From 8796ecb2a9565e04c336c6e84ac606413c9c8c4c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 13:54:17 +0100 Subject: [PATCH 17/27] Ad example for new-config with answered questions --- docs/installation.md | 3 ++- docs/utils.md | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index cbe000da4..8d3d2c464 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -31,7 +31,7 @@ Freqtrade provides the Linux/MacOS Easy Installation script to install all depen !!! Note Windows installation is explained [here](#windows). -The easiest way to install and run Freqtrade is to clone the bot GitHub repository and then run the Easy Installation script, if it's available for your platform. +The easiest way to install and run Freqtrade is to clone the bot Github repository and then run the Easy Installation script, if it's available for your platform. !!! Note "Version considerations" When cloning the repository the default working branch has the name `develop`. This branch contains all last features (can be considered as relatively stable, thanks to automated tests). The `master` branch contains the code of the last release (done usually once per month on an approximately one week old snapshot of the `develop` branch to prevent packaging bugs, so potentially it's more stable). @@ -47,6 +47,7 @@ cd freqtrade git checkout master # Optional, see (1) ./setup.sh --install ``` + (1) This command switches the cloned repository to the use of the `master` branch. It's not needed if you wish to stay on the `develop` branch. You may later switch between branches at any time with the `git checkout master`/`git checkout develop` commands. ## Easy Installation Script (Linux/MacOS) diff --git a/docs/utils.md b/docs/utils.md index 44cbc35d6..f77d2c428 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -54,6 +54,21 @@ optional arguments: !!! Warning Only vital questions are asked. Freqtrade offers a lot more configuration possibilities, which are listed in the [Configuration documentation](configuration.md#configuration-parameters) +### Create config examples + +``` +$ freqtrade new-config --config config_binance.json + +? Do you want to enable Dry-run (simulated trades)? Yes +? Please insert your stake currency: BTC +? Please insert your stake amount: 0.05 +? Please insert max_open_trades (Integer or 'unlimited'): 5 +? Please insert your ticker interval: 15m +? Please insert your display Currency (for reporting): USD +? Select exchange binance +? Do you want to enable Telegram? No +``` + ## Create new strategy Creates a new strategy from a template similar to SampleStrategy. From 929bbe3058e5682793126781956095207d04e3c0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 14:01:19 +0100 Subject: [PATCH 18/27] Link to docker installation from index.md --- docs/index.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index c88c73619..f0ee831e3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -51,12 +51,15 @@ To run this bot we recommend you a cloud instance with a minimum of: ### Software requirements +- Docker (Recommended) + +Alternatively + - Python 3.6.x - pip (pip3) - git - TA-Lib - virtualenv (Recommended) -- Docker (Recommended) ## Support @@ -67,4 +70,4 @@ Click [here](https://join.slack.com/t/highfrequencybot/shared_invite/enQtNjU5ODc ## Ready to try? -Begin by reading our installation guide [here](installation). +Begin by reading our installation guide [for docker](docker.md), or for [installation without docker](installation.md). From c224c669784cdf0383fab61380e3b65d8189f95a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 14:06:31 +0100 Subject: [PATCH 19/27] Small edits to install.md --- docs/installation.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 8d3d2c464..054cafe9b 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -130,6 +130,17 @@ bash setup.sh -i #### 1. Install TA-Lib +Use the provided ta-lib installation script + +```bash +sudo ./build_helpers/install_ta-lib.sh +``` + +!!! Note + This will use the ta-lib tar.gz included in this repository. + +##### TA-Lib manual installation + Official webpage: https://mrjbq7.github.io/ta-lib/install.html ```bash @@ -185,7 +196,8 @@ python3 -m pip install -e . # Initialize the user_directory freqtrade create-userdir --userdir user_data/ -cp config.json.example config.json +# Create a new configuration file +freqtrade new-config --config config.json ``` > *To edit the config please refer to [Bot Configuration](configuration.md).* From cfa6a3e3d32d5575299bb346367ec394ff8a1a7c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 14:12:21 +0100 Subject: [PATCH 20/27] Don't overwrite files --- freqtrade/commands/build_config_commands.py | 6 +++++- tests/commands/test_build_config.py | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index e0910e5b7..6ba9cf0ac 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -166,7 +166,11 @@ def start_new_config(args: Dict[str, Any]) -> None: Create a new strategy from a template Asking the user questions to fill out the templateaccordingly. """ - selections = ask_user_config() config_path = Path(args['config'][0]) + if config_path.exists(): + raise OperationalException( + f"Configuration `{config_path}` already exists. " + "Please use another configuration name or delete the existing configuration.") + selections = ask_user_config() deploy_new_config(config_path, selections) diff --git a/tests/commands/test_build_config.py b/tests/commands/test_build_config.py index 46e79b357..b0a048c15 100644 --- a/tests/commands/test_build_config.py +++ b/tests/commands/test_build_config.py @@ -6,6 +6,7 @@ import pytest from freqtrade.commands.build_config_commands import (ask_user_config, start_new_config) +from freqtrade.exceptions import OperationalException from tests.conftest import get_args, log_has_re @@ -43,6 +44,17 @@ def test_start_new_config(mocker, caplog, exchange): assert result['ticker_interval'] == '15m' +def test_start_new_config_exists(mocker, caplog): + mocker.patch.object(Path, "exists", MagicMock(return_value=True)) + args = [ + "new-config", + "--config", + "coolconfig.json" + ] + with pytest.raises(OperationalException, match=r"Configuration .* already exists\."): + start_new_config(get_args(args)) + + def test_ask_user_config(): # TODO: Implement me pass From d1a3a2d000f1a2e5600265cc4fcf84287fd0122a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 14:22:40 +0100 Subject: [PATCH 21/27] Add tests for build_config --- freqtrade/commands/build_config_commands.py | 23 ++++++++++++++++++--- tests/commands/test_build_config.py | 12 ++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 6ba9cf0ac..838fd510a 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -27,6 +27,19 @@ def validate_is_float(val): return False +def ask_user_overwrite(config_path: Path) -> bool: + questions = [ + { + "type": "confirm", + "name": "overwrite", + "message": f"File {config_path} already exists. Overwrite?", + "default": False, + }, + ] + answers = prompt(questions) + return answers['overwrite'] + + def ask_user_config() -> Dict[str, Any]: """ Ask user a few questions to build the configuration. @@ -169,8 +182,12 @@ def start_new_config(args: Dict[str, Any]) -> None: config_path = Path(args['config'][0]) if config_path.exists(): - raise OperationalException( - f"Configuration `{config_path}` already exists. " - "Please use another configuration name or delete the existing configuration.") + overwrite = ask_user_overwrite(config_path) + if overwrite: + config_path.unlink() + else: + raise OperationalException( + f"Configuration `{config_path}` already exists. " + "Please use another configuration name or delete the existing configuration.") selections = ask_user_config() deploy_new_config(config_path, selections) diff --git a/tests/commands/test_build_config.py b/tests/commands/test_build_config.py index b0a048c15..8f71c2098 100644 --- a/tests/commands/test_build_config.py +++ b/tests/commands/test_build_config.py @@ -1,8 +1,8 @@ -import json from pathlib import Path from unittest.mock import MagicMock import pytest +import rapidjson from freqtrade.commands.build_config_commands import (ask_user_config, start_new_config) @@ -13,7 +13,10 @@ from tests.conftest import get_args, log_has_re @pytest.mark.parametrize('exchange', ['bittrex', 'binance', 'kraken', 'ftx']) def test_start_new_config(mocker, caplog, exchange): wt_mock = mocker.patch.object(Path, "write_text", MagicMock()) - mocker.patch.object(Path, "exists", MagicMock(return_value=False)) + mocker.patch.object(Path, "exists", MagicMock(return_value=True)) + unlink_mock = mocker.patch.object(Path, "unlink", MagicMock()) + mocker.patch('freqtrade.commands.build_config_commands.ask_user_overwrite', return_value=True) + sample_selections = { 'max_open_trades': 3, 'stake_currency': 'USDT', @@ -39,13 +42,16 @@ def test_start_new_config(mocker, caplog, exchange): assert log_has_re("Writing config to .*", caplog) assert wt_mock.call_count == 1 - result = json.loads(wt_mock.call_args_list[0][0][0]) + assert unlink_mock.call_count == 1 + result = rapidjson.loads(wt_mock.call_args_list[0][0][0], + parse_mode=rapidjson.PM_COMMENTS | rapidjson.PM_TRAILING_COMMAS) assert result['exchange']['name'] == exchange assert result['ticker_interval'] == '15m' def test_start_new_config_exists(mocker, caplog): mocker.patch.object(Path, "exists", MagicMock(return_value=True)) + mocker.patch('freqtrade.commands.build_config_commands.ask_user_overwrite', return_value=False) args = [ "new-config", "--config", From 12317b1c535a4ca6b82441896000527c4f69d8cb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 14:46:43 +0100 Subject: [PATCH 22/27] Add some rudimentary tests for questions --- tests/commands/test_build_config.py | 59 ++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/tests/commands/test_build_config.py b/tests/commands/test_build_config.py index 8f71c2098..d4ebe1de2 100644 --- a/tests/commands/test_build_config.py +++ b/tests/commands/test_build_config.py @@ -5,11 +5,33 @@ import pytest import rapidjson from freqtrade.commands.build_config_commands import (ask_user_config, - start_new_config) + ask_user_overwrite, + start_new_config, + validate_is_float, + validate_is_int) from freqtrade.exceptions import OperationalException from tests.conftest import get_args, log_has_re +def test_validate_is_float(): + assert validate_is_float('2.0') + assert validate_is_float('2.1') + assert validate_is_float('0.1') + assert validate_is_float('-0.5') + assert not validate_is_float('-0.5e') + + +def test_validate_is_int(): + assert validate_is_int('2') + assert validate_is_int('6') + assert validate_is_int('-1') + assert validate_is_int('500') + assert not validate_is_int('2.0') + assert not validate_is_int('2.1') + assert not validate_is_int('-2.1') + assert not validate_is_int('-ee') + + @pytest.mark.parametrize('exchange', ['bittrex', 'binance', 'kraken', 'ftx']) def test_start_new_config(mocker, caplog, exchange): wt_mock = mocker.patch.object(Path, "write_text", MagicMock()) @@ -61,7 +83,34 @@ def test_start_new_config_exists(mocker, caplog): start_new_config(get_args(args)) -def test_ask_user_config(): - # TODO: Implement me - pass - # assert ask_user_config() +def test_ask_user_overwrite(mocker): + """ + Once https://github.com/tmbo/questionary/issues/35 is implemented, improve this test. + """ + prompt_mock = mocker.patch('freqtrade.commands.build_config_commands.prompt', + return_value={'overwrite': False}) + assert not ask_user_overwrite(Path('test.json')) + assert prompt_mock.call_count == 1 + + prompt_mock.reset_mock() + prompt_mock = mocker.patch('freqtrade.commands.build_config_commands.prompt', + return_value={'overwrite': True}) + assert ask_user_overwrite(Path('test.json')) + assert prompt_mock.call_count == 1 + + +def test_ask_user_config(mocker): + """ + Once https://github.com/tmbo/questionary/issues/35 is implemented, improve this test. + """ + prompt_mock = mocker.patch('freqtrade.commands.build_config_commands.prompt', + return_value={'overwrite': False}) + answers = ask_user_config() + assert isinstance(answers, dict) + assert prompt_mock.call_count == 1 + + prompt_mock = mocker.patch('freqtrade.commands.build_config_commands.prompt', + return_value={}) + + with pytest.raises(OperationalException, match=r"User interrupted interactive questions\."): + ask_user_config() From 628b06927c08b043338faa11254305bbce948287 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 14:59:14 +0100 Subject: [PATCH 23/27] Support python3.8 virtualenvs and remove config generation via SED --- setup.sh | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/setup.sh b/setup.sh index fb5102e12..bce2e56cf 100755 --- a/setup.sh +++ b/setup.sh @@ -17,6 +17,14 @@ function check_installed_python() { exit 2 fi + which python3.8 + if [ $? -eq 0 ]; then + echo "using Python 3.8" + PYTHON=python3.8 + check_installed_pip + return + fi + which python3.7 if [ $? -eq 0 ]; then echo "using Python 3.7" @@ -215,27 +223,8 @@ function config_generator() { function config() { echo "-------------------------" - echo "Generating config file" + echo "Please use freqtrade new-config -c config.json to generate a new configuration file." echo "-------------------------" - if [ -f config.json ] - then - read -p "A config file already exist, do you want to override it [y/N]? " - if [[ $REPLY =~ ^[Yy]$ ]] - then - config_generator - else - echo "Configuration of config.json ignored." - fi - else - config_generator - fi - - echo - echo "-------------------------" - echo "Config file generated" - echo "-------------------------" - echo "Edit ./config.json to modify Pair and other configurations." - echo } function install() { From cbd2b265bbb2eea78ad6ffc6b727e1b733729ce5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Feb 2020 15:16:44 +0100 Subject: [PATCH 24/27] Fix small error --- freqtrade/commands/arguments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 504c6b0b5..c8a038328 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -182,7 +182,7 @@ class Arguments: # add new-config subcommand build_config_cmd = subparsers.add_parser('new-config', - help="Create new config") + help="Create new config") build_config_cmd.set_defaults(func=start_new_config) self._build_args(optionlist=ARGS_BUILD_CONFIG, parser=build_config_cmd) From 52f4187129566deeed3121752d34e5131410a87e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 8 Feb 2020 13:51:55 +0100 Subject: [PATCH 25/27] Allow exchange templates to configure outside-options too --- freqtrade/commands/build_config_commands.py | 2 +- freqtrade/templates/base_config.json.j2 | 4 +- .../subtemplates/exchange_binance.j2 | 80 ++++++++++--------- .../subtemplates/exchange_generic.j2 | 24 +++--- .../templates/subtemplates/exchange_kraken.j2 | 67 ++++++++-------- 5 files changed, 91 insertions(+), 86 deletions(-) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 838fd510a..7dd1be607 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -90,10 +90,10 @@ def ask_user_config() -> Dict[str, Any]: "name": "exchange_name", "message": "Select exchange", "choices": [ - "bittrex", "binance", "binanceje", "binanceus", + "bittrex", "kraken", Separator(), "other", diff --git a/freqtrade/templates/base_config.json.j2 b/freqtrade/templates/base_config.json.j2 index 1370bfa80..0a4f92c4b 100644 --- a/freqtrade/templates/base_config.json.j2 +++ b/freqtrade/templates/base_config.json.j2 @@ -27,9 +27,7 @@ "sell_profit_only": false, "ignore_roi_if_buy_signal": false }, - "exchange": { - {{ exchange | indent(8) }} - }, + {{ exchange | indent(4) }}, "pairlists": [ {"method": "StaticPairList"} ], diff --git a/freqtrade/templates/subtemplates/exchange_binance.j2 b/freqtrade/templates/subtemplates/exchange_binance.j2 index c527d296b..03aa0560c 100644 --- a/freqtrade/templates/subtemplates/exchange_binance.j2 +++ b/freqtrade/templates/subtemplates/exchange_binance.j2 @@ -1,39 +1,41 @@ -"name": "{{ exchange_name | lower }}", -"key": "{{ exchange_key }}", -"secret": "{{ exchange_secret }}", -"ccxt_config": {"enableRateLimit": true}, -"ccxt_async_config": { - "enableRateLimit": true, - "rateLimit": 200 -}, -"pair_whitelist": [ - "ALGO/BTC", - "ATOM/BTC", - "BAT/BTC", - "BCH/BTC", - "BRD/BTC", - "EOS/BTC", - "ETH/BTC", - "IOTA/BTC", - "LINK/BTC", - "LTC/BTC", - "NEO/BTC", - "NXS/BTC", - "XMR/BTC", - "XRP/BTC", - "XTZ/BTC" -], -"pair_blacklist": [ - "BNB/BTC", - "BNB/BUSD", - "BNB/ETH", - "BNB/EUR", - "BNB/NGN", - "BNB/PAX", - "BNB/RUB", - "BNB/TRY", - "BNB/TUSD", - "BNB/USDC", - "BNB/USDS", - "BNB/USDT", -] +"exchange": { + "name": "{{ exchange_name | lower }}", + "key": "{{ exchange_key }}", + "secret": "{{ exchange_secret }}", + "ccxt_config": {"enableRateLimit": true}, + "ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 200 + }, + "pair_whitelist": [ + "ALGO/BTC", + "ATOM/BTC", + "BAT/BTC", + "BCH/BTC", + "BRD/BTC", + "EOS/BTC", + "ETH/BTC", + "IOTA/BTC", + "LINK/BTC", + "LTC/BTC", + "NEO/BTC", + "NXS/BTC", + "XMR/BTC", + "XRP/BTC", + "XTZ/BTC" + ], + "pair_blacklist": [ + "BNB/BTC", + "BNB/BUSD", + "BNB/ETH", + "BNB/EUR", + "BNB/NGN", + "BNB/PAX", + "BNB/RUB", + "BNB/TRY", + "BNB/TUSD", + "BNB/USDC", + "BNB/USDS", + "BNB/USDT", + ] +} diff --git a/freqtrade/templates/subtemplates/exchange_generic.j2 b/freqtrade/templates/subtemplates/exchange_generic.j2 index 33309de3b..ade9c2f28 100644 --- a/freqtrade/templates/subtemplates/exchange_generic.j2 +++ b/freqtrade/templates/subtemplates/exchange_generic.j2 @@ -1,13 +1,15 @@ -"name": "{{ exchange_name | lower }}", -"key": "{{ exchange_key }}", -"secret": "{{ exchange_secret }}", -"ccxt_config": {"enableRateLimit": true}, -"ccxt_async_config": { - "enableRateLimit": true -}, -"pair_whitelist": [ +"exchange": { + "name": "{{ exchange_name | lower }}", + "key": "{{ exchange_key }}", + "secret": "{{ exchange_secret }}", + "ccxt_config": {"enableRateLimit": true}, + "ccxt_async_config": { + "enableRateLimit": true + }, + "pair_whitelist": [ -], -"pair_blacklist": [ + ], + "pair_blacklist": [ -] + ] +} diff --git a/freqtrade/templates/subtemplates/exchange_kraken.j2 b/freqtrade/templates/subtemplates/exchange_kraken.j2 index 690828887..7139a0830 100644 --- a/freqtrade/templates/subtemplates/exchange_kraken.j2 +++ b/freqtrade/templates/subtemplates/exchange_kraken.j2 @@ -1,33 +1,36 @@ -"name": "kraken", -"key": "{{ exchange_key }}", -"secret": "{{ exchange_secret }}", -"ccxt_config": {"enableRateLimit": true}, -"ccxt_async_config": { - "enableRateLimit": true, - "rateLimit": 1000 -}, -"pair_whitelist": [ - "ADA/EUR", - "ATOM/EUR", - "BAT/EUR", - "BCH/EUR", - "BTC/EUR", - "DAI/EUR", - "DASH/EUR", - "EOS/EUR", - "ETC/EUR", - "ETH/EUR", - "LINK/EUR", - "LTC/EUR", - "QTUM/EUR", - "REP/EUR", - "WAVES/EUR", - "XLM/EUR", - "XMR/EUR", - "XRP/EUR", - "XTZ/EUR", - "ZEC/EUR" -], -"pair_blacklist": [ +"download_trades": true, +"exchange": { + "name": "kraken", + "key": "{{ exchange_key }}", + "secret": "{{ exchange_secret }}", + "ccxt_config": {"enableRateLimit": true}, + "ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 1000 + }, + "pair_whitelist": [ + "ADA/EUR", + "ATOM/EUR", + "BAT/EUR", + "BCH/EUR", + "BTC/EUR", + "DAI/EUR", + "DASH/EUR", + "EOS/EUR", + "ETC/EUR", + "ETH/EUR", + "LINK/EUR", + "LTC/EUR", + "QTUM/EUR", + "REP/EUR", + "WAVES/EUR", + "XLM/EUR", + "XMR/EUR", + "XRP/EUR", + "XTZ/EUR", + "ZEC/EUR" + ], + "pair_blacklist": [ -] + ] +} From 34f04668c19f719f712b34bd556f13c5fb3af1bc Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 8 Feb 2020 14:02:51 +0100 Subject: [PATCH 26/27] Add template for bittrex --- docs/utils.md | 1 - .../subtemplates/exchange_bittrex.j2 | 24 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 freqtrade/templates/subtemplates/exchange_bittrex.j2 diff --git a/docs/utils.md b/docs/utils.md index 66101d9bc..a986f040b 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -40,7 +40,6 @@ optional arguments: Creates a new configuration file, asking some questions which are important selections for a configuration. - ``` usage: freqtrade new-config [-h] [-c PATH] diff --git a/freqtrade/templates/subtemplates/exchange_bittrex.j2 b/freqtrade/templates/subtemplates/exchange_bittrex.j2 new file mode 100644 index 000000000..7a7e8e291 --- /dev/null +++ b/freqtrade/templates/subtemplates/exchange_bittrex.j2 @@ -0,0 +1,24 @@ +"exchange": { + "name": "{{ exchange_name | lower }}", + "key": "{{ exchange_key }}", + "secret": "{{ exchange_secret }}", + "ccxt_config": {"enableRateLimit": true}, + "ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 500 + }, + "pair_whitelist": [ + "ETH/BTC", + "LTC/BTC", + "ETC/BTC", + "DASH/BTC", + "ZEC/BTC", + "XLM/BTC", + "XRP/BTC", + "TRX/BTC", + "ADA/BTC", + "XMR/BTC" + ], + "pair_blacklist": [ + ] +} From b536d501945c502ecc6003f7fea8ffc781f45f02 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 9 Feb 2020 11:41:29 +0100 Subject: [PATCH 27/27] Address PR Review --- freqtrade/commands/build_config_commands.py | 4 ++-- freqtrade/templates/base_config.json.j2 | 2 +- setup.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 7dd1be607..1598fa2ae 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -187,7 +187,7 @@ def start_new_config(args: Dict[str, Any]) -> None: config_path.unlink() else: raise OperationalException( - f"Configuration `{config_path}` already exists. " - "Please use another configuration name or delete the existing configuration.") + f"Configuration file `{config_path}` already exists. " + "Please delete it or use a different configuration file name.") selections = ask_user_config() deploy_new_config(config_path, selections) diff --git a/freqtrade/templates/base_config.json.j2 b/freqtrade/templates/base_config.json.j2 index 0a4f92c4b..88edeb1e8 100644 --- a/freqtrade/templates/base_config.json.j2 +++ b/freqtrade/templates/base_config.json.j2 @@ -19,7 +19,7 @@ "bids_to_ask_delta": 1 } }, - "ask_strategy":{ + "ask_strategy": { "use_order_book": false, "order_book_min": 1, "order_book_max": 9, diff --git a/setup.sh b/setup.sh index bce2e56cf..e120190ce 100755 --- a/setup.sh +++ b/setup.sh @@ -223,7 +223,7 @@ function config_generator() { function config() { echo "-------------------------" - echo "Please use freqtrade new-config -c config.json to generate a new configuration file." + echo "Please use 'freqtrade new-config -c config.json' to generate a new configuration file." echo "-------------------------" }