Merge pull request #2606 from freqtrade/volume_tester
Subcommand: test-pairlist
This commit is contained in:
commit
8dd9b5c6fb
@ -11,14 +11,15 @@ Now you have good Buy and Sell strategies and some historic data, you want to te
|
|||||||
real data. This is what we call
|
real data. This is what we call
|
||||||
[backtesting](https://en.wikipedia.org/wiki/Backtesting).
|
[backtesting](https://en.wikipedia.org/wiki/Backtesting).
|
||||||
|
|
||||||
Backtesting will use the crypto-currencies (pairs) from your config file
|
Backtesting will use the crypto-currencies (pairs) from your config file and load ticker data from `user_data/data/<exchange>` by default.
|
||||||
and load ticker data from `user_data/data/<exchange>` by default.
|
If no data is available for the exchange / pair / ticker interval combination, backtesting will ask you to download them first using `freqtrade download-data`.
|
||||||
If no data is available for the exchange / pair / ticker interval combination, backtesting will
|
|
||||||
ask you to download them first using `freqtrade download-data`.
|
|
||||||
For details on downloading, please refer to the [Data Downloading](data-download.md) section in the documentation.
|
For details on downloading, please refer to the [Data Downloading](data-download.md) section in the documentation.
|
||||||
|
|
||||||
The result of backtesting will confirm if your bot has better odds of making a profit than a loss.
|
The result of backtesting will confirm if your bot has better odds of making a profit than a loss.
|
||||||
|
|
||||||
|
!!! Tip "Using dynamic pairlists for backtesting"
|
||||||
|
While using dynamic pairlists during backtesting is not possible, a dynamic pairlist using current data can be generated via the [`test-pairlist`](utils.md#test-pairlist) command, and needs to be specified as `"pair_whitelist"` attribute in the configuration.
|
||||||
|
|
||||||
### Run a backtesting against the currencies listed in your config file
|
### Run a backtesting against the currencies listed in your config file
|
||||||
|
|
||||||
#### With 5 min tickers (Per default)
|
#### With 5 min tickers (Per default)
|
||||||
|
@ -405,6 +405,9 @@ Inactive markets and blacklisted pairs are always removed from the resulting `pa
|
|||||||
* [`PrecisionFilter`](#precision-filter)
|
* [`PrecisionFilter`](#precision-filter)
|
||||||
* [`PriceFilter`](#price-pair-filter)
|
* [`PriceFilter`](#price-pair-filter)
|
||||||
|
|
||||||
|
!!! Tip "Testing pairlists"
|
||||||
|
Pairlist configurations can be quite tricky to get right. Best use the [`test-pairlist`](utils.md#test-pairlist) subcommand to test your configuration quickly.
|
||||||
|
|
||||||
#### Static Pair List
|
#### Static Pair List
|
||||||
|
|
||||||
By default, the `StaticPairList` method is used, which uses a statically defined pair whitelist from the configuration.
|
By default, the `StaticPairList` method is used, which uses a statically defined pair whitelist from the configuration.
|
||||||
|
@ -43,20 +43,6 @@ The file will be named inline with your class name, and will not overwrite exist
|
|||||||
|
|
||||||
Results will be located in `user_data/strategies/<strategyclassname>.py`.
|
Results will be located in `user_data/strategies/<strategyclassname>.py`.
|
||||||
|
|
||||||
### Sample usage of new-strategy
|
|
||||||
|
|
||||||
```bash
|
|
||||||
freqtrade new-strategy --strategy AwesomeStrategy
|
|
||||||
```
|
|
||||||
|
|
||||||
With custom user directory
|
|
||||||
|
|
||||||
```bash
|
|
||||||
freqtrade new-strategy --userdir ~/.freqtrade/ --strategy AwesomeStrategy
|
|
||||||
```
|
|
||||||
|
|
||||||
### new-strategy complete options
|
|
||||||
|
|
||||||
``` output
|
``` output
|
||||||
usage: freqtrade new-strategy [-h] [--userdir PATH] [-s NAME]
|
usage: freqtrade new-strategy [-h] [--userdir PATH] [-s NAME]
|
||||||
[--template {full,minimal}]
|
[--template {full,minimal}]
|
||||||
@ -75,6 +61,18 @@ optional arguments:
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Sample usage of new-strategy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
freqtrade new-strategy --strategy AwesomeStrategy
|
||||||
|
```
|
||||||
|
|
||||||
|
With custom user directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
freqtrade new-strategy --userdir ~/.freqtrade/ --strategy AwesomeStrategy
|
||||||
|
```
|
||||||
|
|
||||||
## Create new hyperopt
|
## Create new hyperopt
|
||||||
|
|
||||||
Creates a new hyperopt from a template similar to SampleHyperopt.
|
Creates a new hyperopt from a template similar to SampleHyperopt.
|
||||||
@ -82,20 +80,6 @@ The file will be named inline with your class name, and will not overwrite exist
|
|||||||
|
|
||||||
Results will be located in `user_data/hyperopts/<classname>.py`.
|
Results will be located in `user_data/hyperopts/<classname>.py`.
|
||||||
|
|
||||||
### Sample usage of new-hyperopt
|
|
||||||
|
|
||||||
```bash
|
|
||||||
freqtrade new-hyperopt --hyperopt AwesomeHyperopt
|
|
||||||
```
|
|
||||||
|
|
||||||
With custom user directory
|
|
||||||
|
|
||||||
```bash
|
|
||||||
freqtrade new-hyperopt --userdir ~/.freqtrade/ --hyperopt AwesomeHyperopt
|
|
||||||
```
|
|
||||||
|
|
||||||
### new-hyperopt complete options
|
|
||||||
|
|
||||||
``` output
|
``` output
|
||||||
usage: freqtrade new-hyperopt [-h] [--userdir PATH] [--hyperopt NAME]
|
usage: freqtrade new-hyperopt [-h] [--userdir PATH] [--hyperopt NAME]
|
||||||
[--template {full,minimal}]
|
[--template {full,minimal}]
|
||||||
@ -112,6 +96,18 @@ optional arguments:
|
|||||||
`full`.
|
`full`.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Sample usage of new-hyperopt
|
||||||
|
|
||||||
|
```bash
|
||||||
|
freqtrade new-hyperopt --hyperopt AwesomeHyperopt
|
||||||
|
```
|
||||||
|
|
||||||
|
With custom user directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
freqtrade new-hyperopt --userdir ~/.freqtrade/ --hyperopt AwesomeHyperopt
|
||||||
|
```
|
||||||
|
|
||||||
## List Exchanges
|
## List Exchanges
|
||||||
|
|
||||||
Use the `list-exchanges` subcommand to see the exchanges available for the bot.
|
Use the `list-exchanges` subcommand to see the exchanges available for the bot.
|
||||||
@ -234,3 +230,35 @@ $ freqtrade -c config_binance.json list-pairs --all --base BTC ETH --quote USDT
|
|||||||
```
|
```
|
||||||
$ freqtrade list-markets --exchange kraken --all
|
$ freqtrade list-markets --exchange kraken --all
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Test pairlist
|
||||||
|
|
||||||
|
Use the `test-pairlist` subcommand to test the configuration of [dynamic pairlists](configuration.md#pairlists).
|
||||||
|
|
||||||
|
Requires a configuration with specified `pairlists` attribute.
|
||||||
|
Can be used to generate static pairlists to be used during backtesting / hyperopt.
|
||||||
|
|
||||||
|
```
|
||||||
|
usage: freqtrade test-pairlist [-h] [-c PATH]
|
||||||
|
[--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]]
|
||||||
|
[-1] [--print-json]
|
||||||
|
|
||||||
|
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.
|
||||||
|
--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]
|
||||||
|
Specify quote currency(-ies). Space-separated list.
|
||||||
|
-1, --one-column Print output in one column.
|
||||||
|
--print-json Print list of pairs or market symbols in JSON format.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
Show whitelist when using a [dynamic pairlist](configuration.md#pairlists).
|
||||||
|
|
||||||
|
```
|
||||||
|
freqtrade test-pairlist --config config.json --quote USDT BTC
|
||||||
|
```
|
||||||
|
@ -37,6 +37,8 @@ ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"]
|
|||||||
ARGS_LIST_PAIRS = ["exchange", "print_list", "list_pairs_print_json", "print_one_column",
|
ARGS_LIST_PAIRS = ["exchange", "print_list", "list_pairs_print_json", "print_one_column",
|
||||||
"print_csv", "base_currencies", "quote_currencies", "list_pairs_all"]
|
"print_csv", "base_currencies", "quote_currencies", "list_pairs_all"]
|
||||||
|
|
||||||
|
ARGS_TEST_PAIRLIST = ["config", "quote_currencies", "print_one_column", "list_pairs_print_json"]
|
||||||
|
|
||||||
ARGS_CREATE_USERDIR = ["user_data_dir", "reset"]
|
ARGS_CREATE_USERDIR = ["user_data_dir", "reset"]
|
||||||
|
|
||||||
ARGS_BUILD_STRATEGY = ["user_data_dir", "strategy", "template"]
|
ARGS_BUILD_STRATEGY = ["user_data_dir", "strategy", "template"]
|
||||||
@ -63,6 +65,7 @@ class Arguments:
|
|||||||
"""
|
"""
|
||||||
Arguments Class. Manage the arguments received by the cli
|
Arguments Class. Manage the arguments received by the cli
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, args: Optional[List[str]]) -> None:
|
def __init__(self, args: Optional[List[str]]) -> None:
|
||||||
self.args = args
|
self.args = args
|
||||||
self._parsed_arg: Optional[argparse.Namespace] = None
|
self._parsed_arg: Optional[argparse.Namespace] = None
|
||||||
@ -122,7 +125,7 @@ class Arguments:
|
|||||||
from freqtrade.utils import (start_create_userdir, start_download_data,
|
from freqtrade.utils import (start_create_userdir, start_download_data,
|
||||||
start_list_exchanges, start_list_markets,
|
start_list_exchanges, start_list_markets,
|
||||||
start_new_hyperopt, start_new_strategy,
|
start_new_hyperopt, start_new_strategy,
|
||||||
start_list_timeframes, start_trading)
|
start_list_timeframes, start_test_pairlist, start_trading)
|
||||||
from freqtrade.plot.plot_utils import start_plot_dataframe, start_plot_profit
|
from freqtrade.plot.plot_utils import start_plot_dataframe, start_plot_profit
|
||||||
|
|
||||||
subparsers = self.parser.add_subparsers(dest='command',
|
subparsers = self.parser.add_subparsers(dest='command',
|
||||||
@ -211,6 +214,14 @@ class Arguments:
|
|||||||
list_pairs_cmd.set_defaults(func=partial(start_list_markets, pairs_only=True))
|
list_pairs_cmd.set_defaults(func=partial(start_list_markets, pairs_only=True))
|
||||||
self._build_args(optionlist=ARGS_LIST_PAIRS, parser=list_pairs_cmd)
|
self._build_args(optionlist=ARGS_LIST_PAIRS, parser=list_pairs_cmd)
|
||||||
|
|
||||||
|
# Add test-pairlist subcommand
|
||||||
|
test_pairlist_cmd = subparsers.add_parser(
|
||||||
|
'test-pairlist',
|
||||||
|
help='Test your pairlist configuration.',
|
||||||
|
)
|
||||||
|
test_pairlist_cmd.set_defaults(func=start_test_pairlist)
|
||||||
|
self._build_args(optionlist=ARGS_TEST_PAIRLIST, parser=test_pairlist_cmd)
|
||||||
|
|
||||||
# Add download-data subcommand
|
# Add download-data subcommand
|
||||||
download_data_cmd = subparsers.add_parser(
|
download_data_cmd = subparsers.add_parser(
|
||||||
'download-data',
|
'download-data',
|
||||||
|
@ -48,6 +48,7 @@ class PrecisionFilter(IPairList):
|
|||||||
"""
|
"""
|
||||||
Filters and sorts pairlists and assigns and returns them again.
|
Filters and sorts pairlists and assigns and returns them again.
|
||||||
"""
|
"""
|
||||||
|
stoploss = None
|
||||||
if self._config.get('stoploss') is not None:
|
if self._config.get('stoploss') is not None:
|
||||||
# Precalculate sanitized stoploss value to avoid recalculation for every pair
|
# Precalculate sanitized stoploss value to avoid recalculation for every pair
|
||||||
stoploss = 1 - abs(self._config.get('stoploss'))
|
stoploss = 1 - abs(self._config.get('stoploss'))
|
||||||
|
@ -322,3 +322,35 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None:
|
|||||||
args.get('list_pairs_print_json', False) or
|
args.get('list_pairs_print_json', False) or
|
||||||
args.get('print_csv', False)):
|
args.get('print_csv', False)):
|
||||||
print(f"{summary_str}.")
|
print(f"{summary_str}.")
|
||||||
|
|
||||||
|
|
||||||
|
def start_test_pairlist(args: Dict[str, Any]) -> None:
|
||||||
|
"""
|
||||||
|
Test Pairlist configuration
|
||||||
|
"""
|
||||||
|
from freqtrade.pairlist.pairlistmanager import PairListManager
|
||||||
|
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
||||||
|
|
||||||
|
exchange = ExchangeResolver(config['exchange']['name'], config, validate=False).exchange
|
||||||
|
|
||||||
|
quote_currencies = args.get('quote_currencies')
|
||||||
|
if not quote_currencies:
|
||||||
|
quote_currencies = [config.get('stake_currency')]
|
||||||
|
results = {}
|
||||||
|
for curr in quote_currencies:
|
||||||
|
config['stake_currency'] = curr
|
||||||
|
# Do not use ticker_interval set in the config
|
||||||
|
pairlists = PairListManager(exchange, config)
|
||||||
|
pairlists.refresh_pairlist()
|
||||||
|
results[curr] = pairlists.whitelist
|
||||||
|
|
||||||
|
for curr, pairlist in results.items():
|
||||||
|
if not args.get('print_one_column', False):
|
||||||
|
print(f"Pairs for {curr}: ")
|
||||||
|
|
||||||
|
if args.get('print_one_column', False):
|
||||||
|
print('\n'.join(pairlist))
|
||||||
|
elif args.get('list_pairs_print_json', False):
|
||||||
|
print(rapidjson.dumps(list(pairlist), default=str))
|
||||||
|
else:
|
||||||
|
print(pairlist)
|
||||||
|
@ -10,8 +10,9 @@ from freqtrade.utils import (setup_utils_configuration, start_create_userdir,
|
|||||||
start_download_data, start_list_exchanges,
|
start_download_data, start_list_exchanges,
|
||||||
start_list_markets, start_list_timeframes,
|
start_list_markets, start_list_timeframes,
|
||||||
start_new_hyperopt, start_new_strategy,
|
start_new_hyperopt, start_new_strategy,
|
||||||
start_trading)
|
start_test_pairlist, start_trading)
|
||||||
from tests.conftest import get_args, log_has, log_has_re, patch_exchange
|
from tests.conftest import (get_args, log_has, log_has_re, patch_exchange,
|
||||||
|
patched_configuration_load_config_file)
|
||||||
|
|
||||||
|
|
||||||
def test_setup_utils_configuration():
|
def test_setup_utils_configuration():
|
||||||
@ -623,3 +624,36 @@ def test_download_data_trades(mocker, caplog):
|
|||||||
assert dl_mock.call_args[1]['timerange'].starttype == "date"
|
assert dl_mock.call_args[1]['timerange'].starttype == "date"
|
||||||
assert dl_mock.call_count == 1
|
assert dl_mock.call_count == 1
|
||||||
assert convert_mock.call_count == 1
|
assert convert_mock.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_start_test_pairlist(mocker, caplog, markets, tickers, default_conf, capsys):
|
||||||
|
mocker.patch.multiple('freqtrade.exchange.Exchange',
|
||||||
|
markets=PropertyMock(return_value=markets),
|
||||||
|
exchange_has=MagicMock(return_value=True),
|
||||||
|
get_tickers=tickers
|
||||||
|
)
|
||||||
|
|
||||||
|
default_conf['pairlists'] = [
|
||||||
|
{
|
||||||
|
"method": "VolumePairList",
|
||||||
|
"number_assets": 5,
|
||||||
|
"sort_key": "quoteVolume",
|
||||||
|
},
|
||||||
|
{"method": "PrecisionFilter"},
|
||||||
|
{"method": "PriceFilter", "low_price_ratio": 0.02},
|
||||||
|
]
|
||||||
|
|
||||||
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
args = [
|
||||||
|
'test-pairlist',
|
||||||
|
'-c', 'config.json.example'
|
||||||
|
]
|
||||||
|
|
||||||
|
start_test_pairlist(get_args(args))
|
||||||
|
|
||||||
|
assert log_has_re(r"^Using resolved pairlist VolumePairList.*", caplog)
|
||||||
|
assert log_has_re(r"^Using resolved pairlist PrecisionFilter.*", caplog)
|
||||||
|
assert log_has_re(r"^Using resolved pairlist PriceFilter.*", caplog)
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert re.match(r"Pairs for .*", captured.out)
|
||||||
|
assert re.match("['ETH/BTC', 'TKN/BTC', 'BLK/BTC', 'LTC/BTC', 'XRP/BTC']", captured.out)
|
||||||
|
Loading…
Reference in New Issue
Block a user