From 0664a8c0e6e901f807a622469d0f416853b432c6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Oct 2019 15:29:00 +0200 Subject: [PATCH 1/4] add `--fee` to change fees to other values --- freqtrade/configuration/arguments.py | 2 +- freqtrade/configuration/cli_options.py | 6 ++++++ freqtrade/configuration/configuration.py | 7 ++++++- freqtrade/edge/__init__.py | 6 ++++-- freqtrade/optimize/backtesting.py | 7 +++++-- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/freqtrade/configuration/arguments.py b/freqtrade/configuration/arguments.py index da9bef0b0..c2c09eb40 100644 --- a/freqtrade/configuration/arguments.py +++ b/freqtrade/configuration/arguments.py @@ -15,7 +15,7 @@ ARGS_STRATEGY = ["strategy", "strategy_path"] ARGS_MAIN = ARGS_COMMON + ARGS_STRATEGY + ["db_url", "sd_notify"] ARGS_COMMON_OPTIMIZE = ["ticker_interval", "timerange", - "max_open_trades", "stake_amount"] + "max_open_trades", "stake_amount", "fee"] ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions", "strategy_list", "export", "exportfilename"] diff --git a/freqtrade/configuration/cli_options.py b/freqtrade/configuration/cli_options.py index caf34b5e3..9f7f7b82f 100644 --- a/freqtrade/configuration/cli_options.py +++ b/freqtrade/configuration/cli_options.py @@ -144,6 +144,12 @@ AVAILABLE_CLI_OPTIONS = { default=os.path.join('user_data', 'backtest_results', 'backtest-result.json'), ), + "fee": Arg( + '--fee', + help='Specify fee %%. Should be in %%, will be applied twice (on trade entry and exit).', + type=float, + metavar='FLOAT', + ), # Edge "stoploss_range": Arg( '--stoplosses', diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 764593d0f..ccbc41f34 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -210,6 +210,10 @@ class Configuration: logstring='Parameter --stake_amount detected, ' 'overriding stake_amount to: {} ...') + self._args_to_config(config, argname='fee', + logstring='Parameter --fee detected, ' + 'setting fee to: {} ...') + self._args_to_config(config, argname='timerange', logstring='Parameter --timerange detected: {} ...') @@ -323,7 +327,8 @@ class Configuration: sample: logfun=len (prints the length of the found configuration instead of the content) """ - if argname in self.args and self.args[argname]: + if (argname in self.args and self.args[argname] is not None + and self.args[argname] is not False): config.update({argname: self.args[argname]}) if logfun: diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index 66a777ce5..2655fbc65 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -77,8 +77,10 @@ class Edge: self._timerange: TimeRange = TimeRange.parse_timerange("%s-" % arrow.now().shift( days=-1 * self._since_number_of_days).format('YYYYMMDD')) - - self.fee = self.exchange.get_fee() + if config.get('fee'): + self.fee = config['fee'] + else: + self.fee = self.exchange.get_fee() def calculate(self) -> bool: pairs = self.config['exchange']['pair_whitelist'] diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 89aff86f6..759d7b72d 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -63,9 +63,12 @@ class Backtesting: self.config['exchange']['uid'] = '' self.config['dry_run'] = True self.strategylist: List[IStrategy] = [] - self.exchange = ExchangeResolver(self.config['exchange']['name'], self.config).exchange - self.fee = self.exchange.get_fee() + + if config.get('fee'): + self.fee = config['fee'] + else: + self.fee = self.exchange.get_fee() if self.config.get('runmode') != RunMode.HYPEROPT: self.dataprovider = DataProvider(self.config, self.exchange) From 82d4051a39545ae8d3425b66649cff56928c6864 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Oct 2019 15:33:44 +0200 Subject: [PATCH 2/4] Add --fee to documentation --- docs/backtesting.md | 11 +++++++ docs/bot-usage.md | 77 ++++++++++++++++++++++++++------------------- 2 files changed, 55 insertions(+), 33 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 75aba6c73..cc3f11026 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -72,6 +72,17 @@ The exported trades can be used for [further analysis](#further-backtest-result- freqtrade backtesting --export trades --export-filename=backtest_samplestrategy.json ``` +#### Supplying custom fee value + +Sometimes your account has certain fee rabates, which are not visible to ccxt. +To account for this in backtesting, you can use `--fee 0.001` to supply this value to backtesting. +This fee must be a percentage, and will be applied twice (once for trade entry, and once for trade exit). + +```bash +freqtrade backtesting --fee 0.001 +``` + + #### Running backtest with smaller testset by using timerange Use the `--timerange` argument to change how much of the testset you want to use. diff --git a/docs/bot-usage.md b/docs/bot-usage.md index f44400e32..e28ac9970 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -168,22 +168,25 @@ Backtesting also uses the config specified via `-c/--config`. ``` usage: freqtrade backtesting [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE] - [--max_open_trades MAX_OPEN_TRADES] - [--stake_amount STAKE_AMOUNT] [-r] [--eps] [--dmmp] - [-l] - [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]] - [--export EXPORT] [--export-filename PATH] + [--max_open_trades INT] + [--stake_amount STAKE_AMOUNT] [--fee FLOAT] + [--eps] [--dmmp] + [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]] + [--export EXPORT] [--export-filename PATH] optional arguments: -h, --help show this help message and exit -i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL - Specify ticker interval (1m, 5m, 30m, 1h, 1d). + Specify ticker interval (`1m`, `5m`, `30m`, `1h`, + `1d`). --timerange TIMERANGE Specify what timerange of data to use. - --max_open_trades MAX_OPEN_TRADES + --max_open_trades INT Specify max_open_trades to use. --stake_amount STAKE_AMOUNT Specify stake_amount. + --fee FLOAT Specify fee %. Should be in %, will be applied twice + (on trade entry and exit). --eps, --enable-position-stacking Allow buying the same pair multiple times (position stacking). @@ -193,19 +196,21 @@ optional arguments: number). --strategy-list STRATEGY_LIST [STRATEGY_LIST ...] Provide a space-separated list of strategies to - backtest Please note that ticker-interval needs to be + backtest. Please note that ticker-interval needs to be set either in config or via command line. When using - this together with --export trades, the strategy-name - is injected into the filename (so backtest-data.json - becomes backtest-data-DefaultStrategy.json - --export EXPORT Export backtest results, argument are: trades. Example - --export=trades + this together with `--export trades`, the strategy- + name is injected into the filename (so `backtest- + data.json` becomes `backtest-data- + DefaultStrategy.json` + --export EXPORT Export backtest results, argument are: trades. + Example: `--export=trades` --export-filename PATH - Save backtest results to this filename requires - --export to be set as well Example --export- - filename=user_data/backtest_results/backtest_today.json - (default: user_data/backtest_results/backtest- - result.json) + Save backtest results to the file with this filename + (default: `user_data/backtest_results/backtest- + result.json`). Requires `--export` to be set as well. + Example: `--export-filename=user_data/backtest_results + /backtest_today.json` + ``` ### Getting historic data for backtesting @@ -222,13 +227,13 @@ to find optimal parameter values for your stategy. ``` usage: freqtrade hyperopt [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE] [--max_open_trades INT] - [--stake_amount STAKE_AMOUNT] [-r] + [--stake_amount STAKE_AMOUNT] [--fee FLOAT] [--customhyperopt NAME] [--hyperopt-path PATH] [--eps] [-e INT] [-s {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]] - [--dmmp] [--print-all] [--no-color] [-j JOBS] - [--random-state INT] [--min-trades INT] [--continue] - [--hyperopt-loss NAME] + [--dmmp] [--print-all] [--no-color] [--print-json] + [-j JOBS] [--random-state INT] [--min-trades INT] + [--continue] [--hyperopt-loss NAME] optional arguments: -h, --help show this help message and exit @@ -241,6 +246,8 @@ optional arguments: Specify max_open_trades to use. --stake_amount STAKE_AMOUNT Specify stake_amount. + --fee FLOAT Specify fee %. Should be in %, will be applied twice + (on trade entry and exit). --customhyperopt NAME Specify hyperopt class name (default: `DefaultHyperOpts`). @@ -260,6 +267,7 @@ optional arguments: --print-all Print all results, not only the best ones. --no-color Disable colorization of hyperopt results. May be useful if you are redirecting output to a file. + --print-json Print best result detailization in JSON format. -j JOBS, --job-workers JOBS The number of concurrently running jobs for hyperoptimization (hyperopt worker processes). If -1 @@ -278,8 +286,8 @@ optional arguments: generate completely different results, since the target for optimization is different. Built-in Hyperopt-loss-functions are: DefaultHyperOptLoss, - OnlyProfitHyperOptLoss, SharpeHyperOptLoss. - (default: `DefaultHyperOptLoss`). + OnlyProfitHyperOptLoss, SharpeHyperOptLoss.(default: + `DefaultHyperOptLoss`). ``` ## Edge commands @@ -288,25 +296,28 @@ To know your trade expectancy and winrate against historical data, you can use E ``` usage: freqtrade edge [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE] - [--max_open_trades MAX_OPEN_TRADES] - [--stake_amount STAKE_AMOUNT] [-r] - [--stoplosses STOPLOSS_RANGE] + [--max_open_trades INT] [--stake_amount STAKE_AMOUNT] + [--fee FLOAT] [--stoplosses STOPLOSS_RANGE] optional arguments: -h, --help show this help message and exit -i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL - Specify ticker interval (1m, 5m, 30m, 1h, 1d). + Specify ticker interval (`1m`, `5m`, `30m`, `1h`, + `1d`). --timerange TIMERANGE Specify what timerange of data to use. - --max_open_trades MAX_OPEN_TRADES + --max_open_trades INT Specify max_open_trades to use. --stake_amount STAKE_AMOUNT Specify stake_amount. + --fee FLOAT Specify fee %. Should be in %, will be applied twice + (on trade entry and exit). --stoplosses STOPLOSS_RANGE - 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 + Defines a range of stoploss values against which edge + will assess the strategy. The format is "min,max,step" + (without any space). Example: + `--stoplosses=-0.01,-0.1,-0.001` + ``` To understand edge and how to read the results, please read the [edge documentation](edge.md). From 22733e44bf282ae558962e2d62339c3a4d4f5921 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Oct 2019 15:34:31 +0200 Subject: [PATCH 3/4] Add tests for --fee --- freqtrade/configuration/configuration.py | 2 +- tests/optimize/test_backtesting.py | 50 ++++++++++++++---------- tests/optimize/test_edge_cli.py | 10 +++++ tests/test_configuration.py | 2 +- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index ccbc41f34..df461a5ca 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -328,7 +328,7 @@ class Configuration: configuration instead of the content) """ if (argname in self.args and self.args[argname] is not None - and self.args[argname] is not False): + and self.args[argname] is not False): config.update({argname: self.args[argname]}) if logfun: diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index fa40809d8..ff3d14541 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -26,6 +26,21 @@ from tests.conftest import (get_args, log_has, log_has_re, patch_exchange, patched_configuration_load_config_file) +ORDER_TYPES = [ + { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'limit', + 'stoploss_on_exchange': False + }, + { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'limit', + 'stoploss_on_exchange': True + }] + + def trim_dictlist(dict_list, num): new = {} for pair, pair_data in dict_list.items(): @@ -211,7 +226,8 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) -> '--disable-max-market-positions', '--timerange', ':100', '--export', '/bar/foo', - '--export-filename', 'foo_bar.json' + '--export-filename', 'foo_bar.json', + '--fee', '0', ] config = setup_configuration(get_args(args), RunMode.BACKTEST) @@ -243,6 +259,9 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) -> assert 'exportfilename' in config assert log_has('Storing backtest results to {} ...'.format(config['exportfilename']), caplog) + assert 'fee' in config + assert log_has('Parameter --fee detected, setting fee to: {} ...'.format(config['fee']), caplog) + def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None: default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT @@ -277,21 +296,6 @@ def test_start(mocker, fee, default_conf, caplog) -> None: assert start_mock.call_count == 1 -ORDER_TYPES = [ - { - 'buy': 'limit', - 'sell': 'limit', - 'stoploss': 'limit', - 'stoploss_on_exchange': False - }, - { - 'buy': 'limit', - 'sell': 'limit', - 'stoploss': 'limit', - 'stoploss_on_exchange': True - }] - - @pytest.mark.parametrize("order_types", ORDER_TYPES) def test_backtesting_init(mocker, default_conf, order_types) -> None: """ @@ -314,10 +318,6 @@ def test_backtesting_init(mocker, default_conf, order_types) -> None: def test_backtesting_init_no_ticker_interval(mocker, default_conf, caplog) -> None: - """ - Check that stoploss_on_exchange is set to False while backtesting - since backtesting assumes a perfect stoploss anyway. - """ patch_exchange(mocker) del default_conf['ticker_interval'] default_conf['strategy_list'] = ['DefaultStrategy', @@ -330,6 +330,16 @@ def test_backtesting_init_no_ticker_interval(mocker, default_conf, caplog) -> No "or as cli argument `--ticker-interval 5m`", caplog) +def test_tickerdata_with_fee(default_conf, mocker, testdatadir) -> None: + patch_exchange(mocker) + default_conf['fee'] = 0.1234 + + fee_mock = mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.5)) + backtesting = Backtesting(default_conf) + assert backtesting.fee == 0.1234 + assert fee_mock.call_count == 0 + + def test_tickerdata_to_dataframe_bt(default_conf, mocker, testdatadir) -> None: patch_exchange(mocker) timerange = TimeRange(None, 'line', 0, -100) diff --git a/tests/optimize/test_edge_cli.py b/tests/optimize/test_edge_cli.py index 97103da55..2c45a8d51 100644 --- a/tests/optimize/test_edge_cli.py +++ b/tests/optimize/test_edge_cli.py @@ -98,6 +98,16 @@ def test_edge_init(mocker, edge_conf) -> None: assert callable(edge_cli.edge.calculate) +def test_edge_init_fee(mocker, edge_conf) -> None: + patch_exchange(mocker) + edge_conf['fee'] = 0.1234 + edge_conf['stake_amount'] = 20 + fee_mock = mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.5)) + edge_cli = EdgeCli(edge_conf) + assert edge_cli.edge.fee == 0.1234 + assert fee_mock.call_count == 0 + + def test_generate_edge_table(edge_conf, mocker): patch_exchange(mocker) edge_cli = EdgeCli(edge_conf) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 0f2d6a50a..6d2c0ed00 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -403,7 +403,7 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', caplog) - assert 'position_stacking'in config + assert 'position_stacking' in config assert log_has('Parameter --enable-position-stacking detected ...', caplog) assert 'use_max_market_positions' in config From ad35a3d7ab93aafd8a2921d7d452e4de6f00e22e Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 7 Oct 2019 07:02:43 +0200 Subject: [PATCH 4/4] Small wording improvements --- docs/backtesting.md | 2 +- docs/bot-usage.md | 12 ++++++------ freqtrade/configuration/cli_options.py | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index cc3f11026..ec31bec01 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -74,7 +74,7 @@ freqtrade backtesting --export trades --export-filename=backtest_samplestrategy. #### Supplying custom fee value -Sometimes your account has certain fee rabates, which are not visible to ccxt. +Sometimes your account has certain fee rebates (fee reductions starting with a certain account size or monthly volume), which are not visible to ccxt. To account for this in backtesting, you can use `--fee 0.001` to supply this value to backtesting. This fee must be a percentage, and will be applied twice (once for trade entry, and once for trade exit). diff --git a/docs/bot-usage.md b/docs/bot-usage.md index e28ac9970..24c89c018 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -185,8 +185,8 @@ optional arguments: Specify max_open_trades to use. --stake_amount STAKE_AMOUNT Specify stake_amount. - --fee FLOAT Specify fee %. Should be in %, will be applied twice - (on trade entry and exit). + --fee FLOAT Specify fee ratio. Will be applied twice (on trade + entry and exit). --eps, --enable-position-stacking Allow buying the same pair multiple times (position stacking). @@ -246,8 +246,8 @@ optional arguments: Specify max_open_trades to use. --stake_amount STAKE_AMOUNT Specify stake_amount. - --fee FLOAT Specify fee %. Should be in %, will be applied twice - (on trade entry and exit). + --fee FLOAT Specify fee ratio. Will be applied twice (on trade + entry and exit). --customhyperopt NAME Specify hyperopt class name (default: `DefaultHyperOpts`). @@ -310,8 +310,8 @@ optional arguments: Specify max_open_trades to use. --stake_amount STAKE_AMOUNT Specify stake_amount. - --fee FLOAT Specify fee %. Should be in %, will be applied twice - (on trade entry and exit). + --fee FLOAT Specify fee ratio. Will be applied twice (on trade + entry and exit). --stoplosses STOPLOSS_RANGE Defines a range of stoploss values against which edge will assess the strategy. The format is "min,max,step" diff --git a/freqtrade/configuration/cli_options.py b/freqtrade/configuration/cli_options.py index 9f7f7b82f..7c2ba5325 100644 --- a/freqtrade/configuration/cli_options.py +++ b/freqtrade/configuration/cli_options.py @@ -146,7 +146,7 @@ AVAILABLE_CLI_OPTIONS = { ), "fee": Arg( '--fee', - help='Specify fee %%. Should be in %%, will be applied twice (on trade entry and exit).', + help='Specify fee ratio. Will be applied twice (on trade entry and exit).', type=float, metavar='FLOAT', ),